/* Copyright 2010 The glibmm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ _DEFS(glibmm,glib) #include #include #include #include #include #include #include #include #include #include #include namespace Glib { class Bytes; /** @defgroup Variant Variant Data Types * * The Variant classes deal with strongly typed * variant data. A Variant stores a value along with * information about the type of that value. The range of possible * values is determined by the type. The type system used is VariantType. * * See the VariantBase class and its derived types, such as VariantContainerBase, * and the Variant<> template type. * * Variant instances always have a type and a value (which are given * at construction time). The type and value of a Variant * can never change other than by the Variant itself being * destroyed. A Variant cannot contain a pointer. * * Variant is heavily optimised for dealing with data in serialised * form. It works particularly well with data located in memory-mapped * files. It can perform nearly all deserialisation operations in a * small constant time, usually touching only a single memory page. * Serialised Variant data can also be sent over the network. * * Variant is largely compatible with D-Bus. Almost all types of * Variant instances can be sent over D-Bus. See VariantType for * exceptions. * * There is a Python-inspired text language for describing Variant * values. Variant includes a printer for this language and a parser * with type inferencing. */ //Note: We wrap this because it is thrown by GtkBuilder's functions. // See https://bugzilla.gnome.org/show_bug.cgi?id=708206 // It would also be thrown by parse() if we wrap g_variant_parse(). // Now (2014-01-30) it's also thrown by Gio::Action::parse_detailed_name(). /** %Exception class for Variant parse errors. */ _WRAP_GERROR(VariantParseError, GVariantParseError, G_VARIANT_PARSE_ERROR, NO_GTYPE) //TODO: Add this documentation from the API if we are confident of it for the C++ wrapper: // #GVariant is completely threadsafe. A #GVariant instance can be // concurrently accessed in any way from any number of threads without // problems. // Note that we don't copy GVariant's documentation about Memory Use because // it seems easy to get out of sync and people can look at that C documentation if necessary. /** This is the base class for all Variant types. * * If the actual type is known at compile-time then you should use a specific * Variant<>, such as Variant. Otherwise, you may use get_type(), * is_of_type(), or cast_dynamic(). * * @newin{2,28} * @ingroup Variant */ class VariantBase { _CLASS_OPAQUE_COPYABLE(VariantBase, GVariant, NONE, g_variant_ref_sink, g_variant_unref) _CUSTOM_CTOR_CAST() _IGNORE(g_variant_ref, g_variant_ref_sink, g_variant_take_ref, g_variant_unref, g_variant_get, g_variant_get_va) public: /** This typedef is just to make it more obvious that * our operator const void* should be used like operator bool(). */ typedef const void* BoolExpr; /** Test whether the Variant has an underlying instance. * * Mimics usage of pointers: * @code * if (variant) * do_something(); * @endcode * * @newin{2,36} */ operator BoolExpr() const; /** Replace the underlying GVariant. * This is for use by methods that take a VariantBase& as an output * parameter. * * @param cobject The GVariant* obtained from a C function. * @param take_a_reference Whether this method should take a reference, for * instance if the C function has not given one. */ void init(const GVariant* cobject, bool take_a_reference = false); // It's necessary to take an extra reference of the 'const GVariantType*' // returned by g_variant_get_type() because it doesn't do that already. #m4 _CONVERSION(`const GVariantType*',`VariantType',`Glib::wrap(const_cast($3), true)') _WRAP_METHOD(VariantType get_type() const, g_variant_get_type) _WRAP_METHOD(std::string get_type_string() const, g_variant_get_type_string) _WRAP_METHOD(bool is_floating() const, g_variant_is_floating) _WRAP_METHOD(bool is_of_type(const VariantType& type) const, g_variant_is_of_type) _WRAP_METHOD(bool is_container() const, g_variant_is_container) _WRAP_METHOD(GVariantClass classify() const, g_variant_classify) _WRAP_METHOD(gsize get_size() const, g_variant_get_size) _WRAP_METHOD(gconstpointer get_data(), g_variant_get_data, deprecated "Use the const version instead.") _WRAP_METHOD(gconstpointer get_data() const, g_variant_get_data, newin "2,46") _WRAP_METHOD(Glib::RefPtr get_data_as_bytes() const, g_variant_get_data_as_bytes, newin "2,46") _WRAP_METHOD(void store(gpointer data) const, g_variant_store) _WRAP_METHOD(Glib::ustring print(bool type_annotate = false) const, g_variant_print) _IGNORE(g_variant_print_string) #m4 _CONVERSION(`const VariantBase&',`gconstpointer',`const_cast(($3).gobj())') _WRAP_METHOD(guint hash() const, g_variant_hash) /** Checks if @a *this and @a other have the same type and value. * * @newin{2,24} * * @param other The Variant to compare with. * @return true if @a *this and @a other are equal. */ _WRAP_METHOD(bool equal(const VariantBase& other) const, g_variant_equal) /** Gets a VariantBase instance that has the same value as this variant and * is trusted to be in normal form. * * If this variant is already trusted to be in normal form then a new * reference to the variant is returned. * * If this variant is not already trusted, then it is scanned to check if it * is in normal form. If it is found to be in normal form then it is marked * as trusted and a new reference to it is returned. * * If this variant is found not to be in normal form then a new trusted * VariantBase is created with the same value as this variant. * * It makes sense to call this function if you've received variant data from * untrusted sources and you want to ensure your serialised output is * definitely in normal form. * * @param result A location in which to store the trusted VariantBase. * @newin{2,24} */ void get_normal_form(VariantBase& result) const; _IGNORE(g_variant_get_normal_form) _WRAP_METHOD(bool is_normal_form() const, g_variant_is_normal_form) /** Performs a byteswapping operation on the contents of this variant. The * result is that all multi-byte numeric data contained in the variant is * byteswapped. That includes 16, 32, and 64bit signed and unsigned integers * as well as file handles and double precision floating point values. * * This function is an identity mapping on any value that does not contain * multi-byte numeric data. That include strings, booleans, bytes and * containers containing only these things (recursively). * * The returned value is always in normal form and is marked as trusted. * * @param result A location in which to store the byteswapped form of this * variant. * @newin{2,24} */ void byteswap(VariantBase& result) const; _IGNORE(g_variant_byteswap) _WRAP_METHOD(bool check_format_string(const std::string& format_string, bool copy_only = false) const, g_variant_check_format_string) //Ignore private API from gvariant-core.h: _IGNORE(g_variant_is_trusted, g_variant_get_type_info) /** Cast to a specific variant type. * For instance: * @code * Variant derived = VariantBase::cast_dynamic< Variant >(base); * @endcode * * @param v The variant to cast to a specific type. * @result The variant as a specific type. * @throws std::bad_cast if the Variant was not of the expected type. */ template static V_CastTo cast_dynamic(const VariantBase& v) throw(std::bad_cast); _IGNORE(g_variant_dict_new) protected: #ifndef DOXYGEN_SHOULD_SKIP_THIS /** Used by cast_dynamic(). * In addition to an exact match, the following casts are possible: * - VARIANT_TYPE_OBJECT_PATH and VARIANT_TYPE_SIGNATURE can be cast to * VARIANT_TYPE_STRING (Glib::ustring). * - VARIANT_TYPE_STRING, VARIANT_TYPE_OBJECT_PATH and VARIANT_TYPE_SIGNATURE * can be cast to VARIANT_TYPE_BYTESTRING (std::string). * - VARIANT_TYPE_HANDLE can be cast to VARIANT_TYPE_INT32. * * These casts are possible also when they are parts of a more complicated type. * E.g. in Variant > > the map's keys * can be VARIANT_TYPE_OBJECT_PATH and the vector's elements can be VARIANT_TYPE_SIGNATURE. * @newin{2,46} */ bool is_castable_to(const VariantType& supertype) const; #endif //DOXYGEN_SHOULD_SKIP_THIS private: /** Relational operators are deleted to prevent invalid conversion * to const void*. */ bool operator<(const VariantBase& src) const; /// See operator<(). bool operator<=(const VariantBase& src) const; /// See operator<(). bool operator>(const VariantBase& src) const; /// See operator<(). bool operator>=(const VariantBase& src) const; /// See operator<(). bool operator==(const VariantBase& src) const; /// See operator<(). bool operator!=(const VariantBase& src) const; }; template V_CastTo VariantBase::cast_dynamic(const VariantBase& v) throw(std::bad_cast) { if(!(v.gobj())) { return V_CastTo(); } if(v.is_castable_to(V_CastTo::variant_type())) { return V_CastTo(const_cast(v.gobj()), true); } else { throw std::bad_cast(); } } /** Base class from which string variant classes derive. * @newin{2,28} * @ingroup Variant */ class VariantStringBase : public VariantBase { // Trick gmmproc into thinking this is derived from GVariant to wrap some methods. _CLASS_GENERIC(VariantStringBase, GVariant) public: typedef GVariant* CType; typedef VariantStringBase CppType; /// Default constructor. VariantStringBase(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit VariantStringBase(GVariant* castitem, bool take_a_reference = false); /** Creates a D-Bus object path variant with the contents of @a string. @a * string must be a valid D-Bus object path. Use is_object_path() if unsure. * * @param output A location in which to store the new object path variant * instance. * @param object_path A normal nul-terminated string. * @newin{2,28} */ static void create_object_path(VariantStringBase& output, const std::string& object_path); _IGNORE(g_variant_new_object_path) _WRAP_METHOD(static bool is_object_path(const std::string& string), g_variant_is_object_path) /** Creates a D-Bus type signature variant with the contents of @a string. @a * string must be a valid D-Bus type signature. Use is_signature() if unsure. * * @param output A location in which to store the new signature variant * instance. * @param signature A normal nul-terminated string. * @newin{2,28} */ static void create_signature(VariantStringBase& output, const std::string& signature); _IGNORE(g_variant_new_signature) _WRAP_METHOD(static bool is_signature(const std::string& string), g_variant_is_signature) }; /** The base class from which multiple-item Variants derive, such as Variants * containing tuples or arrays. * * @newin{2,28} * @ingroup Variant */ class VariantContainerBase : public VariantBase { // Trick gmmproc into thinking this is derived from GVariant to wrap some methods. _CLASS_GENERIC(VariantContainerBase, GVariant) public: typedef GVariant* CType; typedef VariantContainerBase CppType; /// Default constructor. VariantContainerBase(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit VariantContainerBase(GVariant* castitem, bool take_a_reference = false); /** Create a tuple variant from a vector of its variant children. * @param children The vector containing the children of the container. * @return The newly created tuple variant (as a VariantContainerBase). */ static VariantContainerBase create_tuple(const std::vector& children); /** Create a tuple variant with a single variant child. * @param child The child variant. * @return The newly created tuple variant (as a VariantContainerBase). */ static VariantContainerBase create_tuple(const VariantBase& child); _WRAP_METHOD_DOCS_ONLY(g_variant_new_maybe) static VariantContainerBase create_maybe(const VariantType& child_type, const VariantBase& child = VariantBase()); _WRAP_METHOD(gsize get_n_children() const, g_variant_n_children) /** Reads a child item out of this instance. This method is valid for * variants, maybes, arrays, tuples and dictionary entries. * * It is an error if @a index is greater than the number of child items in * the container. See get_n_children(). * * This function is O(1). * * @param index The index of the child to fetch. * @param child A location in which to store the child at the specified * index. * @throw std::out_of_range * @newin{2,28} */ void get_child(VariantBase& child, gsize index = 0) const; _IGNORE(g_variant_get_child, g_variant_get_child_value) #m4 _CONVERSION(`GVariant*',`VariantBase',`Glib::wrap($3)') _WRAP_METHOD(VariantBase get_child(gsize index = 0), g_variant_get_child_value) /* TODO?: /// A get() method to return the contents of the variant in the container. template DataType get_child(gsize index = 0) const; */ /** If this is a maybe-typed instance, extract its value. If the value is * Nothing, then this function returns false. * * @param maybe A place in which to return the value (the value may be * 0). * @newin{2,28} */ bool get_maybe(VariantBase& maybe) const; _IGNORE(g_variant_get_maybe) protected: #ifndef DOXYGEN_SHOULD_SKIP_THIS /** Used by get_iter() in the subclasses. * @newin{2,46} */ VariantIter get_iter(const VariantType& container_variant_type) const; #endif //DOXYGEN_SHOULD_SKIP_THIS }; template<> VariantContainerBase VariantBase::cast_dynamic(const VariantBase& v) throw(std::bad_cast); /** Template class used for the specialization of the Variant<> classes. * @newin{2,28} * @ingroup Variant */ template class Variant : public VariantBase { public: typedef T CppType; }; /****************** Specializations ***********************************/ /** Specialization of Variant containing a VariantBase. * @newin{2,28} * @ingroup Variant */ template<> class Variant : public VariantContainerBase { // Trick gmmproc into thinking this is derived from GVariant to wrap some methods. _CLASS_GENERIC(Variant, GVariant) public: typedef GVariant* CType; typedef VariantBase CppType; typedef Variant CppContainerType; /// Default constructor. Variant(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant(GVariant* castitem, bool take_a_reference = false); /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; //This must have a create() method because otherwise it would be a copy //constructor. /** Creates a new Variant. * @param data The value of the new Variant. * @return The new Variant. * @newin{2,28} */ static Variant create(const VariantBase& data); _IGNORE(g_variant_new_variant) //TODO: Documentation void get(VariantBase& variant) const; //TODO: Deprecate this in favour of get(VariantBase&)? _WRAP_METHOD(VariantBase get() const, g_variant_get_variant) }; /** Specialization of Variant containing a Variant. * @newin{2,36} * @ingroup Variant */ template class Variant< Variant > : public VariantContainerBase { public: typedef GVariant* CType; typedef Variant CppType; typedef Variant CppContainerType; /// Default constructor. Variant< Variant >(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). * @newin{2,36} */ explicit Variant< Variant >(GVariant* castitem, bool take_a_reference = false); /** Gets the VariantType. * @return The VariantType. * @newin{2,36} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant< Variant >. * @param data The value of the new Variant. * @return The new Variant. * @newin{2,36} */ static Variant< Variant > create(const Variant& data); /** Gets the contents of the Variant. * @return The contents of the Variant. * @newin{2,36} */ Variant get() const; }; /** Specialization of Variant containing a Glib::ustring, for variants of type * string, object path, or signature. * @newin{2,28} * @ingroup Variant */ template<> class Variant : public VariantStringBase { // Trick gmmproc into thinking this is derived from GVariant to wrap some methods. _CLASS_GENERIC(Variant, GVariant) public: typedef char* CType; typedef Glib::ustring CppType; /// Default constructor. Variant(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant(GVariant* castitem, bool take_a_reference = false); /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant. * @param data The value of the new Variant. * @return The new Variant. * @newin{2,28} */ static Variant create(const Glib::ustring& data); //We can't use WRAP_METHOD() here because g_variant_get_string() takes an extra length parameter. /** Gets the contents of the Variant. * @return The contents of the Variant. * @newin{2,28} */ Glib::ustring get() const; _IGNORE(g_variant_get_string, g_variant_dup_string) }; //TODO: When we can break ABI, remove this template specialization. template<> Variant VariantBase::cast_dynamic< Variant >(const VariantBase& v) throw(std::bad_cast); /** Specialization of Variant containing a std::string, for variants of type * bytestring, string, object path, or signature. * See also Variant for UTF-8 strings. * @newin{2,28} * @ingroup Variant */ template<> class Variant : public VariantStringBase { // Trick gmmproc into thinking this is derived from GVariant to wrap some methods. _CLASS_GENERIC(Variant, GVariant) public: typedef char* CType; typedef std::string CppType; /// Default constructor. Variant(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant(GVariant* castitem, bool take_a_reference = false); /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant. * @param data The value of the new Variant. * @return The new Variant. * @newin{2,28} */ static Variant create(const std::string& data); //TODO: Documentation. std::string get() const; _IGNORE(g_variant_get_bytestring, g_variant_dup_bytestring) }; //TODO: When we can break ABI, remove this template specialization. template<> Variant VariantBase::cast_dynamic< Variant >(const VariantBase& v) throw(std::bad_cast); /** Specialization of Variant containing a dictionary entry. See also * Variant< std::map >. * @newin{2,28} * @ingroup Variant */ template class Variant< std::pair > : public VariantContainerBase { public: typedef std::pair CppType; typedef Variant CppContainerType; /// Default constructor. Variant< std::pair >() : VariantContainerBase() {} /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant< std::pair >(GVariant* castitem, bool take_a_reference = false) : VariantContainerBase(castitem, take_a_reference) {} /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant< std::pair >. * @param data The value of the new Variant. * @return The new Variant. * @newin{2,28} */ static Variant< std::pair > create(const std::pair& data); _IGNORE(g_variant_new_dict_entry) /** Gets the contents of the Variant. * @return The contents of the Variant. * @throw std::out_of_range * @newin{2,28} */ std::pair get() const; }; /** Specialization of Variant containing an array of items. * @newin{2,28} * @ingroup Variant */ template class Variant< std::vector > : public VariantContainerBase { public: typedef T CppType; typedef std::vector CppContainerType; /// Default constructor. Variant< std::vector >() : VariantContainerBase() {} /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant< std::vector >(GVariant* castitem, bool take_a_reference = false) : VariantContainerBase(castitem, take_a_reference) {} /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant from an array of numeric types. * @param data The array to use for creation. * @return The new Variant. * @newin{2,28} */ static Variant< std::vector > create(const std::vector& data); _IGNORE(g_variant_new_array) /** Gets a specific element of the array. It is an error if @a index is * greater than the number of child items in the container. See * VariantContainerBase::get_n_children(). * * This function is O(1). * * @param index The index of the element. * @return The element at index @a index. * @throw std::out_of_range * @newin{2,28} */ T get_child(gsize index) const; /** Gets the vector of the Variant. * @return The vector. * @newin{2,28} */ std::vector get() const; _IGNORE(g_variant_get_fixed_array) /** Gets a VariantIter of the Variant. * @return the VaraintIter. * @newin{2,28} */ VariantIter get_iter() const; }; /** Specialization of Variant containing an array of UTF-8 capable * strings. * @newin{2,28} * @ingroup Variant */ template<> class Variant< std::vector > : public VariantContainerBase { public: typedef Glib::ustring CppType; typedef std::vector CppContainerType; /// Default constructor. Variant< std::vector >(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant< std::vector >(GVariant* castitem, bool take_a_reference = false); /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant from an array of strings. * @param data The array to use for creation. * @return The new Variant. * @newin{2,28} */ static Variant< std::vector > create(const std::vector& data); /** Gets a specific element of the string array. It is an error if @a index * is greater than the number of child items in the container. See * VariantContainerBase::get_n_children(). * * This function is O(1). * * @param index The index of the element. * @return The element at index @a index. * @throw std::out_of_range * @newin{2,28} */ Glib::ustring get_child(gsize index) const; /** Gets the string vector of the Variant. * @return The vector. * @newin{2,28} */ std::vector get() const; _IGNORE(g_variant_get_strv, g_variant_dup_strv) /** Gets a VariantIter of the Variant. * @return the VaraintIter. * @newin{2,28} */ VariantIter get_iter() const; }; /** Specialization of Variant containing an array of non-UTF-8 strings * (byte string arrays). * @newin{2,28} * @ingroup Variant */ template<> class Variant< std::vector > : public VariantContainerBase { public: typedef std::string CppType; typedef std::vector CppContainerType; /// Default constructor. Variant< std::vector >(); /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant< std::vector >(GVariant* castitem, bool take_a_reference = false); /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant from an array of strings. * @param data The array to use for creation. * @return The new Variant. * @newin{2,28} */ static Variant< std::vector > create(const std::vector& data); /** Creates a new Variant from an array of D-Bus object paths. * @param paths The array to use for creation. * @return The new Variant. * @newin{2,36} */ static Variant< std::vector > create_from_object_paths(const std::vector& paths); /** Gets a specific element of the string array. It is an error if @a index * is greater than the number of child items in the container. See * VariantContainerBase::get_n_children(). * * This function is O(1). * * @param index The index of the element. * @return The element at index @a index. * @throw std::out_of_range * @newin{2,28} */ std::string get_child(gsize index) const; /** Gets the string vector of the Variant. * @return The vector. * @newin{2,28} */ std::vector get() const; _IGNORE(g_variant_get_bytestring_array, g_variant_dup_bytestring_array) // Object paths are merely strings so it is possible to get them already with // the existing get() methods in this class. _IGNORE(g_variant_get_objv, g_variant_dup_objv) /** Gets a VariantIter of the Variant. * @return the VaraintIter. * @newin{2,28} */ VariantIter get_iter() const; }; /** Specialization of Variant containing a dictionary (a map of (key, * value) elements). * @newin{2,28} * @ingroup Variant */ template class Variant< std::map >: public VariantContainerBase { public: typedef std::pair CppType; typedef std::map CppContainerType; /// Default constructor. Variant< std::map >() : VariantContainerBase() {} /** GVariant constructor. * @param castitem The GVariant to wrap. * @param take_a_reference Whether to take an extra reference of the * GVariant or not (not taking one could destroy the GVariant with the * wrapper). */ explicit Variant< std::map >(GVariant* castitem, bool take_a_reference = false) : VariantContainerBase(castitem, take_a_reference) {} /** Gets the VariantType. * @return The VariantType. * @newin{2,28} */ static const VariantType& variant_type() G_GNUC_CONST; /** Creates a new Variant containing a dictionary from a map. * @param data The map to use for creation. * @return The new Variant holding a dictionary. * @newin{2,28} */ static Variant< std::map > create(const std::map& data); /** Gets a specific dictionary entry from the string array. It is an error * if @a index is greater than the number of child items in the container. * See VariantContainerBase::get_n_children(). * * This function is O(1). * * @param index The index of the element. * @return The dictionary entry at index @a index. * @throw std::out_of_range * @newin{2,28} */ std::pair get_child(gsize index) const; /** Looks up a value in a dictionary Variant. * @param key The key to look up. * @param value A location in which to store the value if found. * @return true if the key is found, false otherwise. */ bool lookup(const K& key, V& value) const; _IGNORE(g_variant_lookup_value, g_variant_lookup) /** Gets the map (the dictionary) of the Variant. * @return The vector. * @newin{2,28} */ std::map get() const; /** Gets a VariantIter of the Variant. * @return the VaraintIter. * @newin{2,28} */ VariantIter get_iter() const; }; } // namespace Glib //We ignore g_variant_get_*() methods that are wrapped by Variant<> specializations, such as in variant_basictypes.h.m4. _IGNORE( g_variant_get_boolean, g_variant_get_byte, g_variant_get_int16, g_variant_get_uint16, g_variant_get_int32, g_variant_get_handle, g_variant_get_uint32, g_variant_get_int64, g_variant_get_uint64, g_variant_get_double, g_variant_iter_new ) /* Include generated specializations of Variant<> for fundamental types: */ #define _GLIBMM_VARIANT_H_INCLUDE_VARIANT_BASICTYPES_H #include #undef _GLIBMM_VARIANT_H_INCLUDE_VARIANT_BASICTYPES_H namespace Glib { /*--------------------Variant< Variant >---------------------*/ template Variant< Variant >::Variant() : VariantContainerBase() { } template Variant< Variant >::Variant(GVariant* castitem, bool take_a_reference) : VariantContainerBase(castitem, take_a_reference) { } // static template const VariantType& Variant< Variant >::variant_type() { return VARIANT_TYPE_VARIANT; } template Variant< Variant > Variant< Variant >::create(const Variant& data) { Variant< Variant > result = Variant< Variant >( g_variant_new_variant(const_cast(data.gobj()))); return result; } template Variant Variant< Variant >::get() const { GVariant* const gvariant = g_variant_get_variant(gobject_); return Variant(gvariant); } /*--------------------Variant< std::pair >---------------------*/ // static template const VariantType& Variant< std::pair >::variant_type() { static VariantType type( g_variant_type_new_dict_entry(Variant::variant_type().gobj(), Variant::variant_type().gobj())); return type; } template Variant< std::pair > Variant< std::pair >::create(const std::pair& data) { Variant key = Variant::create(data.first); Variant value = Variant::create(data.second); Variant< std::pair > result = Variant< std::pair >( g_variant_new_dict_entry(key.gobj(), value.gobj())); return result; } template std::pair Variant< std::pair >::get() const { // Get the key (the first element of this VariantContainerBase). Variant key; VariantContainerBase::get_child(key, 0); // Get the value (the second element of this VariantContainerBase). Variant value; VariantContainerBase::get_child(value, 1); std::pair result(key.get(), value.get()); return result; } /*---------------------Variant< std::vector >---------------------*/ // static template const VariantType& Variant< std::vector >::variant_type() { static VariantType type = VariantType::create_array(Variant::variant_type()); return type; } template Variant< std::vector > Variant< std::vector >::create(const std::vector& data) { // Get the variant type of the array. VariantType array_variant_type = Variant< std::vector >::variant_type(); // Create a GVariantBuilder to build the array. GVariantBuilder* builder = g_variant_builder_new(array_variant_type.gobj()); // Add the elements of the vector into the builder. for(const auto& element : data) { Glib::Variant variant = Glib::Variant::create(element); g_variant_builder_add_value(builder, variant.gobj()); } // Create the variant using the builder. Variant< std::vector > result = Variant< std::vector >(g_variant_new( reinterpret_cast(array_variant_type.gobj()), builder)); g_variant_builder_unref(builder); return result; } template T Variant< std::vector >::get_child(gsize index) const { if(index >= g_variant_n_children(const_cast(gobj()))) throw std::out_of_range( "Variant< std::vector >::get_child(): Index out of bounds."); Glib::Variant variant; GVariant* gvariant = g_variant_get_child_value(const_cast(gobj()), index); variant.init(gvariant); return variant.get(); } template std::vector Variant< std::vector >::get() const { std::vector result; gsize n_children = g_variant_n_children(const_cast(gobj())); for(gsize i = 0; i < n_children; i++) { Glib::Variant variant; GVariant* gvariant = g_variant_get_child_value(const_cast(gobj()), i); variant.init(gvariant); result.push_back(variant.get()); } return result; } template VariantIter Variant< std::vector >::get_iter() const { return VariantContainerBase::get_iter(variant_type()); } /*---------------------Variant< std::map > --------------------*/ // static template const VariantType& Variant< std::map >::variant_type() { static VariantType type = VariantType::create_array(Variant< std::pair >::variant_type()); return type; } template Variant< std::map > Variant< std::map >::create(const std::map& data) { // Get the variant type of the elements. VariantType element_variant_type = Variant< std::pair >::variant_type(); // Get the variant type of the array. VariantType array_variant_type = Variant< std::map >::variant_type(); // Create a GVariantBuilder to build the array. GVariantBuilder* builder = g_variant_builder_new(array_variant_type.gobj()); // Add the elements of the map into the builder. for(const auto& element : data) { auto dict_entry = Variant< std::pair >::create(element); g_variant_builder_add_value(builder, dict_entry.gobj()); } // Create the variant using the builder. Variant< std::map > result = Variant< std::map >(g_variant_new( reinterpret_cast(array_variant_type.gobj()), builder)); g_variant_builder_unref(builder); return result; } template std::pair Variant< std::map >::get_child(gsize index) const { Variant< std::pair > dict_entry; VariantContainerBase::get_child(dict_entry, index); return dict_entry.get(); } template bool Variant< std::map >::lookup(const K& key, V& value) const { // The code in this method pretty much reflects the g_variant_lookup_value() // function except that it's more general to deal with keys that are not // just strings. VariantIter iter = get_iter(); Variant< std::pair > entry; while(iter.next_value(entry)) { std::pair element = entry.get(); if(element.first == key) { value = element.second; return true; } } return false; } template std::map Variant< std::map >::get() const { std::map result; VariantIter iter = get_iter(); Variant< std::pair > entry; while(iter.next_value(entry)) { result.insert(entry.get()); } return result; } template VariantIter Variant< std::map >::get_iter() const { return VariantContainerBase::get_iter(variant_type()); } } // namespace Glib