c++-gtk-utils
|
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 59 Temple Place - Suite 330, Boston, MA, 02111-1307, 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*/