c++-gtk-utils
gvar_handle.h
Go to the documentation of this file.
00001 /* Copyright (C) 2010 and 2011 Chris Vine
00002 
00003 The library comprised in this file or of which this file is part is
00004 distributed by Chris Vine under the GNU Lesser General Public
00005 License as follows:
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public License
00009    as published by the Free Software Foundation; either version 2.1 of
00010    the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful, but
00013    WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License, version 2.1, for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License, version 2.1, along with this library (see the file LGPL.TXT
00019    which came with this source code package in the c++-gtk-utils
00020    sub-directory); if not, write to the Free Software Foundation, Inc.,
00021    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00022 
00023 However, it is not intended that the object code of a program whose
00024 source code instantiates a template from this file or uses macros or
00025 inline functions (of any length) should by reason only of that
00026 instantiation or use be subject to the restrictions of use in the GNU
00027 Lesser General Public License.  With that in mind, the words "and
00028 macros, inline functions and instantiations of templates (of any
00029 length)" shall be treated as substituted for the words "and small
00030 macros and small inline functions (ten lines or less in length)" in
00031 the fourth paragraph of section 5 of that licence.  This does not
00032 affect any other reason why object code may be subject to the
00033 restrictions in that licence (nor for the avoidance of doubt does it
00034 affect the application of section 2 of that licence to modifications
00035 of the source code in this file).
00036 
00037 */
00038 
00039 #ifndef CGU_GVAR_HANDLE_H
00040 #define CGU_GVAR_HANDLE_H
00041 
00042 #include <functional> // for std::less and std::hash<T*>
00043 #include <cstddef>    // for std::size_t
00044 
00045 #include <glib.h>
00046 
00047 #if defined(DOXYGEN_PARSING) || GLIB_CHECK_VERSION(2,24,0)
00048 
00049 #include <c++-gtk-utils/cgu_config.h>
00050 
00051 /**
00052  * @addtogroup handles handles and smart pointers
00053  */
00054 
00055 namespace Cgu {
00056 
00057 /**
00058  * @class GvarHandle gvar_handle.h c++-gtk-utils/gvar_handle.h
00059  * @brief This is a handle for managing the reference count of
00060  * GVariant objects.
00061  * @ingroup handles
00062  * @sa GobjHandle
00063  *
00064  * This is a class which manages the reference count of GVariant
00065  * objects.  It does not maintain its own reference count, but
00066  * interfaces with that kept by the GVariant object.
00067  *
00068  * GVariant objects created with one of the g_variant_new*() functions
00069  * are created with a floating reference.  The constructor of a
00070  * GvarHandle which takes a pointer will automatically take
00071  * ownership of such a newly created GVariant object, by calling
00072  * g_variant_ref_sink().
00073  *
00074  * GVariant objects which are obtained by one of the g_variant_get*()
00075  * or similar getter functions, such as g_variant_get_child_value(),
00076  * g_variant_get_variant(), g_variant_get() with a "v" or "(v)" format
00077  * string, or g_variant_iter_next_value(), or as the return value of a
00078  * dbus method call in gio's dbus implementation such as
00079  * g_dbus_connection_call_sync(), g_dbus_connection_call_finish(),
00080  * g_dbus_proxy_call_sync() or g_dbus_proxy_call_finish(), are not
00081  * created with a floating reference (the variant normally already
00082  * exists), but instead the reference count is incremented by the
00083  * function concerned when the object is passed out to the user, so
00084  * giving ownership to the user.
00085  *
00086  * It follows that g_variant_ref_sink() is not called by the
00087  * constructor taking a pointer if the floating reference has already
00088  * been sunk.  This behaviour will ensure that the handle behaves the
00089  * same whether it is passed a GVariant object from one of the
00090  * g_variant_new*() functions, or from one of the g_variant_get*() and
00091  * other getter functions mentioned above.  One consequence is that if
00092  * the constructor taking a pointer is passed a pointer which has
00093  * already been passed to and is managed by another GvarHandle object,
00094  * the user must call g_variant_ref() herself explicitly: but GVariant
00095  * objects already owned by a GvarHandle should not normally be passed
00096  * to another GvarHandle that way, as GvarHandles have a copy
00097  * constructor and assignment operator which will increment the
00098  * reference count automatically.
00099  *
00100  * In other words, invoke the constructor taking a pointer only with a
00101  * newly created GVariant object, or with a GVariant object directly
00102  * handed out by a GVariant getter function or as the return value of
00103  * a gio dbus method call, and everything else will take care of
00104  * itself.  In this respect, GvarHandles work the same way as
00105  * conventional shared pointer implementations managing objects
00106  * allocated on free store.  The same applies to the reset() method.
00107  *
00108  * Because glib and gio themselves increment the reference count of a
00109  * GVariant object where they need to take ownership, an
00110  * already-managed object held by a GvarHandle can safely be passed by
00111  * pointer as the first argument of one of glib's g_variant_*()
00112  * functions or as an argument to one of gio's dbus functions, and
00113  * that is one of its intended usages.  For that purpose, the pointer
00114  * can be obtained by means of the operatorT*() type conversion
00115  * operator (which returns the underlying pointer), or by explicitly
00116  * calling the get() method to obtain the underlying pointer.
00117  *
00118  * By automatically handling GVariant reference counts, GvarHandle
00119  * makes GVariant objects exception-safe, and they also permit
00120  * GVariant objects to be kept in standard C++ containers.
00121  *
00122  * GVariant objects are thread safe, including their reference counts.
00123  * This means that a GVariant object may be held by GvarHandles in
00124  * containers in different threads, and accessed concurrently in those
00125  * different threads.
00126  *
00127  * Typical usage might be, for example, as follows:
00128  *
00129  * @code
00130  *    // execute a method "TwoInts" taking two 'int' arguments and
00131  *    // returning a string-array via g_dbus_proxy_call_sync()
00132  *    gint32 a = 2;
00133  *    gint32 b = 10;
00134  *    Cgu::GvarHandle result(g_dbus_proxy_call_sync(proxy,
00135  *                                                 "TwoInts",
00136  *                                                 g_variant_new("(ii)", a, b),
00137  *                                                 G_DBUS_CALL_FLAGS_NONE,
00138  *                                                 -1,
00139  *                                                 0,
00140  *                                                 0));
00141  *    if (!result.get()) {
00142  *      g_critical("Failed to execute method TwoInts");
00143  *      execute_error_strategy();
00144  *    }
00145  *    else {
00146  *      // gio's dbus implementation wraps all return
00147  *      // values in a tuple: first extract the string-array
00148  *      // from the tuple
00149  *      Cgu::GvarHandle sa_variant(g_variant_get_child_value(result, 0));
00150  *      // free str_arr with g_strfreev()
00151  *      gchar** str_arr = g_variant_dup_strv(sa_variant, 0);
00152  *    }
00153  * @endcode
00154  *
00155  * Further examples of the use of GvarHandle, see @ref Variants
00156  *
00157  * @note This class is only available if glib >= 2.24.0 is installed.
00158  */
00159 
00160 class GvarHandle {
00161 
00162   GVariant* obj_p;
00163 
00164   void unreference() {
00165     if (obj_p) g_variant_unref(obj_p);
00166   }
00167 
00168   void reference() {
00169     if (obj_p) g_variant_ref(obj_p);
00170   }
00171 
00172 public:
00173 
00174  /**
00175   * The constructor does not throw.  g_variant_ref_sink() is called if
00176   * the managed object has a floating reference.
00177   * @param ptr The GVariant object which the GvarHandle is to manage
00178   * (if any).
00179   * @note The pointer passed, if not NULL, should not normally already
00180   * have been given to and so managed by any other GvarHandle object.
00181   * Use the copy constructor instead instead in that case.
00182   */
00183   explicit GvarHandle(GVariant* ptr = 0) {
00184     obj_p = ptr;
00185 
00186     // if an object with a floating reference has been passed to this constructor,
00187     // take ownership of it
00188     if (ptr && g_variant_is_floating(ptr)) {
00189       g_variant_ref_sink(ptr);
00190     }
00191   }
00192 
00193  /**
00194   * Causes the handle to cease to manage its managed object (if any)
00195   * and decrements its reference count, so destroying it if the
00196   * reference count thereby becomes 0.  If the argument passed is not
00197   * NULL, the handle will manage the new GVariant object passed and
00198   * g_variant_ref_sink() is called if the new object has a floating
00199   * reference.  This method does not throw.
00200   * @param ptr NULL (the default), or a new GVariant object to manage.
00201   * @note The pointer passed, if not NULL, should not normally already
00202   * have been given to and so managed by any other GvarHandle object.
00203   * Use the assignment operator instead in that case.
00204   */
00205   void reset(GVariant* ptr = 0) {
00206     
00207     unreference();
00208     obj_p = ptr;
00209 
00210     // if an object with a floating reference has been passed to this method,
00211     // take ownership of it
00212     if (ptr && g_variant_is_floating(ptr)) {
00213       g_variant_ref_sink(ptr);
00214     }
00215   }
00216 
00217  /**
00218   * The copy constructor does not throw.  It increments the reference
00219   * count of the managed object.
00220   * @param gvar The handle to be copied.
00221   */
00222   GvarHandle(const GvarHandle& gvar) {
00223     obj_p = gvar.obj_p;
00224     reference();
00225   }
00226 
00227  /**
00228   * The move constructor does not throw.  It has move semantics.
00229   * @param gvar The handle to be moved.
00230   */
00231   GvarHandle(GvarHandle&& gvar) {
00232     obj_p = gvar.obj_p;
00233     gvar.obj_p = 0;
00234   }
00235 
00236  /**
00237   * This method does not throw.  It decrements the reference count of
00238   * the former managed object (if any), so destroying it if the
00239   * reference count thereby becomes 0, and increments the reference
00240   * count of the new managed GVariant object.
00241   * @param gvar The assignor.
00242   * @return The GvarHandle object after assignment.
00243   */
00244   GvarHandle& operator=(const GvarHandle& gvar) {
00245 
00246     // check whether we are already referencing this object -
00247     // if so make this a null op.  This will also deal with
00248     // self-assignment
00249     if (obj_p != gvar.obj_p) {
00250 
00251       // first unreference any object referenced by this handle
00252       unreference();
00253 
00254       // now inherit the GVariant from the assigning handle
00255       // and reference it
00256       obj_p = gvar.obj_p;
00257       reference();
00258     }
00259     return *this;
00260   }
00261 
00262  /**
00263   * This method does not throw.  It decrements the reference count of
00264   * the former managed object (if any), so destroying it if the
00265   * reference count thereby becomes 0, and has move semantics with
00266   * respect to the new managed object.
00267   * @param gvar The handle to be moved.
00268   * @return The GvarHandle object after the move operation.
00269   */
00270   GvarHandle& operator=(GvarHandle&& gvar) {
00271 
00272     // check for self-assignment
00273     if (this != &gvar) {
00274 
00275       // first unreference any object referenced by this handle
00276       unreference();
00277 
00278       // now inherit the GVariant from the moving handle
00279       obj_p = gvar.obj_p;
00280       gvar.obj_p = 0;
00281     }
00282     return *this;
00283   }
00284 
00285  /**
00286   * This method does not throw.
00287   * @return A pointer to the handled GVariant object (or NULL if none
00288   * is handled).
00289   */
00290   GVariant* get() const {return obj_p;}
00291 
00292  /**
00293   * This method does not throw.
00294   * @return A pointer to the handled GVariant object (or NULL if none
00295   * is handled).
00296   */
00297   operator GVariant*() const {return obj_p;}
00298 
00299  /**
00300   * The destructor does not throw.  It decrements the reference count
00301   * of the managed object (if any), so destroying it if the reference
00302   * count thereby becomes 0.
00303   */
00304   ~GvarHandle() {unreference();}
00305 };
00306 
00307 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
00308 
00309 // we can use built-in operator == when comparing pointers referencing
00310 // different objects of the same type
00311 /**
00312  * @ingroup handles
00313  *
00314  * This comparison operator does not throw.  It compares the addresses
00315  * of the managed objects.
00316  *
00317  * Since 2.0.0-rc2
00318  */
00319 inline bool operator==(const GvarHandle& h1, const GvarHandle& h2) {
00320   return (h1.get() == h2.get());
00321 }
00322 
00323 /**
00324  * @ingroup handles
00325  *
00326  * This comparison operator does not throw.  It compares the addresses
00327  * of the managed objects.
00328  *
00329  * Since 2.0.0-rc2
00330  */
00331 inline bool operator!=(const GvarHandle& h1, const GvarHandle& h2) {
00332   return !(h1 == h2);
00333 }
00334 
00335 // we must use std::less rather than the < built-in operator for
00336 // pointers to objects not within the same array or object: "For
00337 // templates greater, less, greater_equal, and less_equal, the
00338 // specializations for any pointer type yield a total order, even if
00339 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
00340 /**
00341  * @ingroup handles
00342  *
00343  * This comparison operator does not throw.  It compares the addresses
00344  * of the managed objects.
00345  *
00346  * Since 2.0.0-rc2
00347  */
00348 inline bool operator<(const GvarHandle& h1, const GvarHandle& h2) {
00349   return std::less<GVariant*>()(h1.get(), h2.get());
00350 }
00351 
00352 #endif // CGU_USE_SMART_PTR_COMPARISON
00353 
00354 } // namespace Cgu
00355 
00356 // doxygen produces long filenames that tar can't handle:
00357 // we have generic documentation for std::hash specialisations
00358 // in doxygen.main.in
00359 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
00360 /* This struct allows GvarHandle objects to be keys in unordered
00361    associative containers */
00362 namespace std {
00363 template <>
00364 struct hash<Cgu::GvarHandle> {
00365   typedef std::size_t result_type;
00366   typedef Cgu::GvarHandle argument_type;
00367   result_type operator()(const argument_type& h) const {
00368     // this is fine: std::hash structs do not normally contain data and
00369     // std::hash<T*> certainly won't, so we don't have overhead constructing
00370     // std::hash<T*> on the fly
00371     return std::hash<GVariant*>()(h.get());
00372   }
00373  };
00374 } // namespace std
00375 #endif // CGU_USE_SMART_PTR_COMPARISON
00376 
00377 #else
00378 #warning GvarHandle not available: glib >= 2.24.0 is required
00379 #endif /*GLIB_CHECK_VERSION(2,24,0)*/
00380 
00381 #endif /*CGU_GVAR_HANDLE_H*/