c++-gtk-utils
gvar_handle.h
Go to the documentation of this file.
1 /* Copyright (C) 2010 and 2011 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36 
37 */
38 
39 #ifndef CGU_GVAR_HANDLE_H
40 #define CGU_GVAR_HANDLE_H
41 
42 #include <functional> // for std::less and std::hash<T*>
43 #include <cstddef> // for std::size_t
44 
45 #include <glib.h>
46 
47 #if defined(DOXYGEN_PARSING) || GLIB_CHECK_VERSION(2,24,0)
48 
50 
51 /**
52  * @addtogroup handles handles and smart pointers
53  */
54 
55 namespace Cgu {
56 
57 /**
58  * @class GvarHandle gvar_handle.h c++-gtk-utils/gvar_handle.h
59  * @brief This is a handle for managing the reference count of
60  * GVariant objects.
61  * @ingroup handles
62  * @sa GobjHandle
63  *
64  * This is a class which manages the reference count of GVariant
65  * objects. It does not maintain its own reference count, but
66  * interfaces with that kept by the GVariant object.
67  *
68  * GVariant objects created with one of the g_variant_new*() functions
69  * are created with a floating reference. The constructor of a
70  * GvarHandle which takes a pointer will automatically take
71  * ownership of such a newly created GVariant object, by calling
72  * g_variant_ref_sink().
73  *
74  * GVariant objects which are obtained by one of the g_variant_get*()
75  * or similar getter functions, such as g_variant_get_child_value(),
76  * g_variant_get_variant(), g_variant_get() with a "v" or "(v)" format
77  * string, or g_variant_iter_next_value(), or as the return value of a
78  * dbus method call in gio's dbus implementation such as
79  * g_dbus_connection_call_sync(), g_dbus_connection_call_finish(),
80  * g_dbus_proxy_call_sync() or g_dbus_proxy_call_finish(), are not
81  * created with a floating reference (the variant normally already
82  * exists), but instead the reference count is incremented by the
83  * function concerned when the object is passed out to the user, so
84  * giving ownership to the user.
85  *
86  * It follows that g_variant_ref_sink() is not called by the
87  * constructor taking a pointer if the floating reference has already
88  * been sunk. This behaviour will ensure that the handle behaves the
89  * same whether it is passed a GVariant object from one of the
90  * g_variant_new*() functions, or from one of the g_variant_get*() and
91  * other getter functions mentioned above. One consequence is that if
92  * the constructor taking a pointer is passed a pointer which has
93  * already been passed to and is managed by another GvarHandle object,
94  * the user must call g_variant_ref() herself explicitly: but GVariant
95  * objects already owned by a GvarHandle should not normally be passed
96  * to another GvarHandle that way, as GvarHandles have a copy
97  * constructor and assignment operator which will increment the
98  * reference count automatically.
99  *
100  * In other words, invoke the constructor taking a pointer only with a
101  * newly created GVariant object, or with a GVariant object directly
102  * handed out by a GVariant getter function or as the return value of
103  * a gio dbus method call, and everything else will take care of
104  * itself. In this respect, GvarHandles work the same way as
105  * conventional shared pointer implementations managing objects
106  * allocated on free store. The same applies to the reset() method.
107  *
108  * Because glib and gio themselves increment the reference count of a
109  * GVariant object where they need to take ownership, an
110  * already-managed object held by a GvarHandle can safely be passed by
111  * pointer as the first argument of one of glib's g_variant_*()
112  * functions or as an argument to one of gio's dbus functions, and
113  * that is one of its intended usages. For that purpose, the pointer
114  * can be obtained by means of the operatorT*() type conversion
115  * operator (which returns the underlying pointer), or by explicitly
116  * calling the get() method to obtain the underlying pointer.
117  *
118  * By automatically handling GVariant reference counts, GvarHandle
119  * makes GVariant objects exception-safe, and they also permit
120  * GVariant objects to be kept in standard C++ containers.
121  *
122  * GVariant objects are thread safe, including their reference counts.
123  * This means that a GVariant object may be held by GvarHandles in
124  * containers in different threads, and accessed concurrently in those
125  * different threads.
126  *
127  * Typical usage might be, for example, as follows:
128  *
129  * @code
130  * // execute a method "TwoInts" taking two 'int' arguments and
131  * // returning a string-array via g_dbus_proxy_call_sync()
132  * gint32 a = 2;
133  * gint32 b = 10;
134  * Cgu::GvarHandle result(g_dbus_proxy_call_sync(proxy,
135  * "TwoInts",
136  * g_variant_new("(ii)", a, b),
137  * G_DBUS_CALL_FLAGS_NONE,
138  * -1,
139  * 0,
140  * 0));
141  * if (!result.get()) {
142  * g_critical("Failed to execute method TwoInts");
143  * execute_error_strategy();
144  * }
145  * else {
146  * // gio's dbus implementation wraps all return
147  * // values in a tuple: first extract the string-array
148  * // from the tuple
149  * Cgu::GvarHandle sa_variant(g_variant_get_child_value(result, 0));
150  * // free str_arr with g_strfreev()
151  * gchar** str_arr = g_variant_dup_strv(sa_variant, 0);
152  * }
153  * @endcode
154  *
155  * Further examples of the use of GvarHandle, see @ref Variants
156  *
157  * @note This class is only available if glib >= 2.24.0 is installed.
158  */
159 
160 class GvarHandle {
161 
162  GVariant* obj_p;
163 
164  void unreference() noexcept {
165  if (obj_p) g_variant_unref(obj_p);
166  }
167 
168  void reference() noexcept {
169  if (obj_p) g_variant_ref(obj_p);
170  }
171 
172 public:
173 
174  /**
175  * The constructor does not throw. g_variant_ref_sink() is called if
176  * the managed object has a floating reference.
177  * @param ptr The GVariant object which the GvarHandle is to manage
178  * (if any).
179  * @note The pointer passed, if not NULL, should not normally already
180  * have been given to and so managed by any other GvarHandle object.
181  * Use the copy constructor instead instead in that case.
182  */
183  explicit GvarHandle(GVariant* ptr = 0) noexcept {
184  obj_p = ptr;
185 
186  // if an object with a floating reference has been passed to this constructor,
187  // take ownership of it
188  if (ptr && g_variant_is_floating(ptr)) {
189  g_variant_ref_sink(ptr);
190  }
191  }
192 
193  /**
194  * Causes the handle to cease to manage its managed object (if any)
195  * and decrements its reference count, so destroying it if the
196  * reference count thereby becomes 0. If the argument passed is not
197  * NULL, the handle will manage the new GVariant object passed and
198  * g_variant_ref_sink() is called if the new object has a floating
199  * reference. This method does not throw.
200  * @param ptr NULL (the default), or a new GVariant object to manage.
201  * @note The pointer passed, if not NULL, should not normally already
202  * have been given to and so managed by any other GvarHandle object.
203  * Use the assignment operator instead in that case.
204  */
205  void reset(GVariant* ptr = 0) noexcept {
206 
207  unreference();
208  obj_p = ptr;
209 
210  // if an object with a floating reference has been passed to this method,
211  // take ownership of it
212  if (ptr && g_variant_is_floating(ptr)) {
213  g_variant_ref_sink(ptr);
214  }
215  }
216 
217  /**
218  * The copy constructor does not throw. It increments the reference
219  * count of the managed object.
220  * @param gvar The handle to be copied.
221  */
222  GvarHandle(const GvarHandle& gvar) noexcept {
223  obj_p = gvar.obj_p;
224  reference();
225  }
226 
227  /**
228  * The move constructor does not throw. It has move semantics.
229  * @param gvar The handle to be moved.
230  */
231  GvarHandle(GvarHandle&& gvar) noexcept {
232  obj_p = gvar.obj_p;
233  gvar.obj_p = 0;
234  }
235 
236  /**
237  * This method does not throw. It decrements the reference count of
238  * the former managed object (if any), so destroying it if the
239  * reference count thereby becomes 0, and increments the reference
240  * count of the new managed GVariant object.
241  * @param gvar The assignor.
242  * @return The GvarHandle object after assignment.
243  */
244  GvarHandle& operator=(const GvarHandle& gvar) noexcept {
245 
246  // check whether we are already referencing this object -
247  // if so make this a null op. This will also deal with
248  // self-assignment
249  if (obj_p != gvar.obj_p) {
250 
251  // first unreference any object referenced by this handle
252  unreference();
253 
254  // now inherit the GVariant from the assigning handle
255  // and reference it
256  obj_p = gvar.obj_p;
257  reference();
258  }
259  return *this;
260  }
261 
262  /**
263  * This method does not throw. It decrements the reference count of
264  * the former managed object (if any), so destroying it if the
265  * reference count thereby becomes 0, and has move semantics with
266  * respect to the new managed object.
267  * @param gvar The handle to be moved.
268  * @return The GvarHandle object after the move operation.
269  */
270  GvarHandle& operator=(GvarHandle&& gvar) noexcept {
271 
272  // check for self-assignment
273  if (this != &gvar) {
274 
275  // first unreference any object referenced by this handle
276  unreference();
277 
278  // now inherit the GVariant from the moving handle
279  obj_p = gvar.obj_p;
280  gvar.obj_p = 0;
281  }
282  return *this;
283  }
284 
285  /**
286  * This method does not throw.
287  * @return A pointer to the handled GVariant object (or NULL if none
288  * is handled).
289  */
290  GVariant* get() const noexcept {return obj_p;}
291 
292  /**
293  * This method does not throw.
294  * @return A pointer to the handled GVariant object (or NULL if none
295  * is handled).
296  */
297  operator GVariant*() const noexcept {return obj_p;}
298 
299  /**
300  * The destructor does not throw. It decrements the reference count
301  * of the managed object (if any), so destroying it if the reference
302  * count thereby becomes 0.
303  */
304  ~GvarHandle() {unreference();}
305 };
306 
307 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
308 
309 // we can use built-in operator == when comparing pointers referencing
310 // different objects of the same type
311 /**
312  * @ingroup handles
313  *
314  * This comparison operator does not throw. It compares the addresses
315  * of the managed objects.
316  *
317  * Since 2.0.0-rc2
318  */
319 inline bool operator==(const GvarHandle& h1, const GvarHandle& h2) noexcept {
320  return (h1.get() == h2.get());
321 }
322 
323 /**
324  * @ingroup handles
325  *
326  * This comparison operator does not throw. It compares the addresses
327  * of the managed objects.
328  *
329  * Since 2.0.0-rc2
330  */
331 inline bool operator!=(const GvarHandle& h1, const GvarHandle& h2) noexcept {
332  return !(h1 == h2);
333 }
334 
335 // we must use std::less rather than the < built-in operator for
336 // pointers to objects not within the same array or object: "For
337 // templates greater, less, greater_equal, and less_equal, the
338 // specializations for any pointer type yield a total order, even if
339 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
340 /**
341  * @ingroup handles
342  *
343  * This comparison operator does not throw unless std::less applied to
344  * pointer types throws (which it would not do with any sane
345  * implementation). It compares the addresses of the managed objects.
346  *
347  * Since 2.0.0-rc2
348  */
349 inline bool operator<(const GvarHandle& h1, const GvarHandle& h2) {
350  return std::less<GVariant*>()(h1.get(), h2.get());
351 }
352 
353 #endif // CGU_USE_SMART_PTR_COMPARISON
354 
355 } // namespace Cgu
356 
357 // doxygen produces long filenames that tar can't handle:
358 // we have generic documentation for std::hash specialisations
359 // in doxygen.main.in
360 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
361 /* This struct allows GvarHandle objects to be keys in unordered
362  associative containers */
363 namespace std {
364 template <>
365 struct hash<Cgu::GvarHandle> {
366  typedef std::size_t result_type;
367  typedef Cgu::GvarHandle argument_type;
368  result_type operator()(const argument_type& h) const {
369  // this is fine: std::hash structs do not normally contain data and
370  // std::hash<T*> certainly won't, so we don't have overhead constructing
371  // std::hash<T*> on the fly
372  return std::hash<GVariant*>()(h.get());
373  }
374  };
375 } // namespace std
376 #endif // CGU_USE_SMART_PTR_COMPARISON
377 
378 #else
379 #warning GvarHandle not available: glib >= 2.24.0 is required
380 #endif /*GLIB_CHECK_VERSION(2,24,0)*/
381 
382 #endif /*CGU_GVAR_HANDLE_H*/
Cgu::GvarHandle::operator=
GvarHandle & operator=(GvarHandle &&gvar) noexcept
Definition: gvar_handle.h:270
Cgu
Definition: application.h:44
Cgu::GvarHandle::get
GVariant * get() const noexcept
Definition: gvar_handle.h:290
Cgu::GvarHandle::GvarHandle
GvarHandle(const GvarHandle &gvar) noexcept
Definition: gvar_handle.h:222
Cgu::operator<
bool operator<(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:632
Cgu::operator!=
bool operator!=(const GobjHandle< T > &h1, const GobjHandle< T > &h2) noexcept
Definition: gobj_handle.h:613
Cgu::operator==
bool operator==(const GobjHandle< T > &h1, const GobjHandle< T > &h2) noexcept
Definition: gobj_handle.h:600
Cgu::GvarHandle::GvarHandle
GvarHandle(GVariant *ptr=0) noexcept
Definition: gvar_handle.h:183
hash
A specialization of std::hash for Cgu::Callback::FunctorArg, Cgu::Callback::SafeFunctorArg,...
Cgu::GvarHandle::~GvarHandle
~GvarHandle()
Definition: gvar_handle.h:304
Cgu::GvarHandle::reset
void reset(GVariant *ptr=0) noexcept
Definition: gvar_handle.h:205
Cgu::GvarHandle::GvarHandle
GvarHandle(GvarHandle &&gvar) noexcept
Definition: gvar_handle.h:231
Cgu::GvarHandle
This is a handle for managing the reference count of GVariant objects.
Definition: gvar_handle.h:160
cgu_config.h
Cgu::GvarHandle::operator=
GvarHandle & operator=(const GvarHandle &gvar) noexcept
Definition: gvar_handle.h:244