c++-gtk-utils
|
00001 /* Copyright (C) 2005 to 2012 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_GOBJ_HANDLE_H 00040 #define CGU_GOBJ_HANDLE_H 00041 00042 #include <exception> 00043 #include <functional> // for std::less and std::hash<T*> 00044 #include <cstddef> // for std::size_t 00045 00046 #include <glib-object.h> 00047 00048 #include <c++-gtk-utils/cgu_config.h> 00049 00050 /** 00051 * @addtogroup handles handles and smart pointers 00052 */ 00053 00054 namespace Cgu { 00055 00056 /** 00057 * @class GobjHandle gobj_handle.h c++-gtk-utils/gobj_handle.h 00058 * @brief This is a handle for managing the reference count of 00059 * GObjects. 00060 * @ingroup handles 00061 * @sa MainWidgetBase GobjWeakHandle 00062 * 00063 * This is a class which manages the reference count of GObjects. It 00064 * does not maintain its own reference count, but interfaces with that 00065 * kept by the glib object system. 00066 * 00067 * GobjHandles are most useful to manage GObjects which are not also 00068 * GtkWidgets or GInitiallyUnowned objects - GtkWidgets and 00069 * GInitiallyUnowned objects have initial floating references which 00070 * will result in them being automatically managed by the container in 00071 * which they are held. Nonetheless, GobjHandles can be used to hold 00072 * GtkWidgets and GInitiallyUnowned objects, as the constructor of a 00073 * GobjHandle which takes a pointer will automatically take ownership 00074 * of a newly created GtkWidget or GInitiallyUnowned object, by 00075 * calling g_object_ref_sink(). Plain GObjects do not need to be sunk 00076 * to be owned by the GobjHandle. 00077 * 00078 * Note that g_object_ref_sink() is not called by the constructor 00079 * taking a pointer if the floating reference has already been sunk, 00080 * so if that constructor is passed an object already owned by a GTK+ 00081 * container it will be necessary to call g_object_ref() on it 00082 * explicitly. This behaviour will ensure that the handle behaves the 00083 * same whether it is holding a plain GObject, or it is holding a 00084 * GInitiallyUnowned/GtkWidget object. Generally however, where an 00085 * object is already owned by a container, the object should be passed 00086 * by another handle - ie by the copy constructor (or by the 00087 * assignment operator), as those always increment the reference count 00088 * automatically. 00089 * 00090 * In other words, invoke the constructor taking a pointer only with a 00091 * newly created object (whether a GObject, GInitiallyUnowned or 00092 * GtkWidget object), and everything else will take care of itself. In 00093 * this respect, GobjHandles work the same way as conventional shared 00094 * pointer implementations managing objects allocated on free store. 00095 * The same applies to the reset() method. (Care is required however 00096 * if initializing a Cgu::GobjHandle with a widget or GObject object 00097 * obtained from GtkBuilder, since these are not "newly created" in 00098 * this sense. It is necessary to call g_object_ref() by hand in that 00099 * case, since GtkBuilder does not by itself pass ownership of any 00100 * objects it creates.) 00101 * 00102 * Because any GTK+ containers themselves increment the reference 00103 * count of a GObject or GtkWidget where they need to take ownership, 00104 * an already-managed object held by a GobjHandle can safely be passed 00105 * by pointer to a GTK+ container, and that is one of the intended 00106 * usages. For that purpose, although the class has operator*() and 00107 * operator->() dereferencing operators, and so has normal smart 00108 * pointer functionality, as it is intended for use with the normal C 00109 * GObject/pango/GTK+ interfaces, ordinary use would involve passing 00110 * the handle to a function taking a pointer by means of the 00111 * operatorT*() type conversion operator (which returns the underlying 00112 * pointer), or by explicitly calling the get() method to obtain the 00113 * underlying pointer. 00114 * 00115 * The principal intended usage of GobjHandle is to automatically 00116 * handle GObject reference counts and therefore to make GObjects 00117 * exception-safe, but they also permit GObjects/GtkWidgets to be kept 00118 * in standard C++ containers. 00119 * 00120 * As of glib-2.8, g_object_ref() and g_object_unref() are thread 00121 * safe, so with glib-2.8 or greater there can be different GobjHandle 00122 * instances in different threads referencing the same GObject object. 00123 * Of course, if that is done, this does not affect the need (or 00124 * otherwise) in the particular use in question to lock anything other 00125 * than the reference count - say when accessing the referenced object 00126 * itself in different threads. 00127 * 00128 * Typical usage might be, for example, as follows: 00129 * 00130 * @code 00131 * using namespace Cgu; 00132 * GobjHandle<GtkListStore> store(gtk_list_store_new(1, G_TYPE_STRING)); 00133 * 00134 * [ ... fill the list store ... ] 00135 * 00136 * GobjHandle<GtkWidget> view(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store.get())); 00137 * // 'view' will take sole ownership of the list store when 'store' goes out of scope, or 00138 * // 'store' could be kept alive so that the list store will survive removal from the view 00139 * 00140 * [ ... set up an interface including a GtkVBox 'vbox' which will hold the tree view ... ] 00141 * 00142 * gtk_container_add(GTK_CONTAINER(vbox), view); 00143 * // 'vbox' will take sole ownership of the tree view when 'view' goes out of scope, or 00144 * // 'view' could be kept alive so that the tree view will survive removal from the vbox 00145 * @endcode 00146 */ 00147 00148 template <class T> class GobjHandle { 00149 00150 T* obj_p; 00151 00152 void unreference() { 00153 if (obj_p) g_object_unref(G_OBJECT(obj_p)); 00154 } 00155 00156 void reference() { 00157 if (obj_p) g_object_ref(G_OBJECT(obj_p)); 00158 } 00159 00160 public: 00161 00162 /** 00163 * The constructor does not throw. g_object_ref_sink() is called if 00164 * the managed object has a floating reference. 00165 * @param ptr The object which the GobjHandle is to manage (if any). 00166 * @note The object passed should not normally be already owned by a 00167 * GTK+ container or managed by any other GobjHandle object. If it 00168 * is, g_object_ref() must be called explicitly by the user code. 00169 */ 00170 explicit GobjHandle(T* ptr = 0) { 00171 obj_p = ptr; 00172 00173 // if an object with a floating reference has been passed to this constructor, 00174 // take ownership of it 00175 if (ptr && g_object_is_floating(G_OBJECT(ptr))) { 00176 g_object_ref_sink(G_OBJECT(ptr)); 00177 } 00178 } 00179 00180 /** 00181 * Causes the handle to cease to manage its managed object (if any) 00182 * and decrements its reference count, so destroying it if the 00183 * reference count thereby becomes 0. If the argument passed is not 00184 * NULL, the handle will manage the new object passed and 00185 * g_object_ref_sink() is called if the new object has a floating 00186 * reference. This method does not throw. 00187 * @param ptr NULL (the default), or a new object to manage. 00188 * @note The new object passed should not normally be already owned 00189 * by a GTK+ container or managed by any other GobjHandle object. If 00190 * it is, g_object_ref() must be called explicitly by the user code. 00191 */ 00192 void reset(T* ptr = 0) { 00193 00194 unreference(); 00195 obj_p = ptr; 00196 00197 // if an object with a floating reference has been passed to this method, 00198 // take ownership of it 00199 if (ptr && g_object_is_floating(G_OBJECT(ptr))) { 00200 g_object_ref_sink(G_OBJECT(ptr)); 00201 } 00202 } 00203 00204 /** 00205 * The copy constructor does not throw. It increments the reference 00206 * count of the managed object. 00207 * @param gobj The handle to be copied. 00208 */ 00209 GobjHandle(const GobjHandle& gobj) { 00210 obj_p = gobj.obj_p; 00211 reference(); 00212 } 00213 00214 /** 00215 * The move constructor does not throw. It has move semantics. 00216 * @param gobj The handle to be moved. 00217 */ 00218 GobjHandle(GobjHandle&& gobj) { 00219 obj_p = gobj.obj_p; 00220 gobj.obj_p = 0; 00221 } 00222 00223 // We don't have a constructor for GobjHandle taking a GobjWeakHandle 00224 // object. If we did that, we would have to remove the GobjWeakHandle 00225 // constructor taking a pointer so we know that its tracked object 00226 // always has an owner when initialising a new GobjHandle with the 00227 // GobjWeakHandle, so we can in turn know we can increase the reference 00228 // count when initialising the GobjHandle. However, removing that 00229 // constructor would be inconsistent with one of the purposes of having 00230 // a GobjWeakHandle class. For the same reason, we don't have an 00231 // assignment operator for GobjHandle taking such an object. 00232 /** 00233 * This method does not throw. It decrements the reference count of 00234 * the former managed object (if any), so destroying it if the 00235 * reference count thereby becomes 0, and increments the reference 00236 * count of the new managed object. 00237 * @param gobj The assignor. 00238 * @return The GobjHandle object after assignment. 00239 */ 00240 GobjHandle& operator=(const GobjHandle& gobj) { 00241 00242 // check whether we are already referencing this object - 00243 // if so make this a null op. This will also deal with 00244 // self-assignment 00245 if (obj_p != gobj.obj_p) { 00246 00247 // first unreference any object referenced by this handle 00248 unreference(); 00249 00250 // now inherit the GObject from the assigning handle 00251 // and reference it 00252 obj_p = gobj.obj_p; 00253 reference(); 00254 } 00255 return *this; 00256 } 00257 00258 /** 00259 * This method does not throw. It decrements the reference count of 00260 * the former managed object (if any), so destroying it if the 00261 * reference count thereby becomes 0, and has move semantics with 00262 * respect to the new managed object. 00263 * @param gobj The handle to be moved. 00264 * @return The GobjHandle object after the move operation. 00265 */ 00266 GobjHandle& operator=(GobjHandle&& gobj) { 00267 00268 // check for self-assignment 00269 if (this != &gobj) { 00270 00271 // first unreference any object referenced by this handle 00272 unreference(); 00273 00274 // now inherit the GObject from the moving handle 00275 obj_p = gobj.obj_p; 00276 gobj.obj_p = 0; 00277 } 00278 return *this; 00279 } 00280 00281 /** 00282 * This method does not throw. 00283 * @return A pointer to the handled GObject (or NULL if none is 00284 * handled). 00285 */ 00286 T* get() const {return obj_p;} 00287 00288 /** 00289 * This method does not throw. 00290 * @return A reference to the handled GObject. 00291 */ 00292 T& operator*() const {return *obj_p;} 00293 00294 /** 00295 * This method does not throw. 00296 * @return A pointer to the handled GObject (or NULL if none is 00297 * handled). 00298 */ 00299 T* operator->() const {return obj_p;} 00300 00301 /** 00302 * This method does not throw. 00303 * @return A pointer to the handled GObject (or NULL if none is 00304 * handled). 00305 */ 00306 operator T*() const {return obj_p;} 00307 00308 /** 00309 * The destructor does not throw. It decrements the reference count 00310 * of the managed object (if any), so destroying it if the reference 00311 * count thereby becomes 0. 00312 */ 00313 ~GobjHandle() {unreference();} 00314 }; 00315 00316 /** 00317 * @class GobjWeakHandle gobj_handle.h c++-gtk-utils/gobj_handle.h 00318 * @brief This is a handle for managing weak references to GObjects. 00319 * @ingroup handles 00320 * @sa GobjHandle 00321 * 00322 * This class tracks a GObject, so that if that GObject no longer 00323 * exists then operator bool() or the valid() method will return 00324 * false, but does not take a strong reference by incrementing the 00325 * reference count to the GObject and so take ownership of it. It has 00326 * two main use areas: first, in order to break reference cycles that 00327 * may otherwise arise if two classes would otherwise hold strong 00328 * references to each other. Secondly, to manage a pointer to a 00329 * GObject returned by a GTK+ getter function where ownership is not 00330 * passed (that is, where the user is not expected to call 00331 * g_object_unref() when finished with the return value). A typical 00332 * example of this is the GtkTreeSelection object returned by 00333 * gtk_tree_view_get_selection(). The GtkTreeSelection object is part 00334 * of the GtkTreeView's implemention and will become invalid as soon 00335 * as the GtkTreeView object is finalized. 00336 * 00337 * As in the case of the GobjHandle class, although this class has 00338 * operator*() and operator->() dereferencing operators, and so has 00339 * normal smart pointer functionality, as it is intended for use with 00340 * the normal C GObject/pango/GTK+ interfaces, ordinary use would 00341 * involve passing the handle to a function taking a pointer by means 00342 * of the operatorT*() type conversion operator (which returns the 00343 * underlying pointer), or by explicitly calling the get() method to 00344 * obtain the underlying pointer. 00345 * 00346 * Typical usage is as follows: 00347 * 00348 * @code 00349 * using namespace Cgu; 00350 * GobjWeakHandle<GtkTreeSelection> s(gtk_tree_view_get_selection(tree_view)); 00351 * gtk_tree_selection_set_mode(s, GTK_SELECTION_SINGLE); 00352 * ... 00353 * 00354 * [some code blocks later] 00355 * if (s) { // check that the GtkTreeSelection object still exists. 00356 * GtkTreeIter iter; 00357 * GtkTreeModel* model = 0; 00358 * gtk_tree_selection_get_selected(s, &model, &iter); 00359 * ... 00360 * } 00361 * else [report error]; 00362 * @endcode 00363 * 00364 * Or instead of an 'if' block, GobjWeakHandleError could be caught: 00365 * 00366 * @code 00367 * using namespace Cgu; 00368 * GobjWeakHandle<GtkTreeSelection> s(gtk_tree_view_get_selection(tree_view)); 00369 * gtk_tree_selection_set_mode(s, GTK_SELECTION_SINGLE); 00370 * ... 00371 * 00372 * [some code blocks later] 00373 * GtkTreeIter iter; 00374 * GtkTreeModel* model = 0; 00375 * try { 00376 * gtk_tree_selection_get_selected(s, &model, &iter); 00377 * ... 00378 * } 00379 * catch (GobjWeakHandleError&) {[report error]} 00380 * @endcode 00381 * 00382 * @b Thread-safe @b use 00383 * 00384 * This class wraps 00385 * g_object_add_weak_pointer()/g_object_remove_weak_pointer(), and as 00386 * those GObject functions have practical limitations concerning 00387 * thread-safe use, this class has the same practical limitations. As 00388 * shown above, typical usage for a weak pointer 's' would be 'if (s) 00389 * do_it(s)', but if the thread calling that sequence (thread A) were 00390 * not the thread controlling the lifetime of the referenced GObject 00391 * (thread B), then thread B may have destroyed the GObject between 00392 * thread A testing 's' and then calling the referenced object. The 00393 * same applies to the test leading to GobjWeakHandleError being 00394 * thrown. 00395 * 00396 * In other words, in the GtkTreeSelection code example above, if the 00397 * thread calling gtk_tree_selection_get_selected() were not the main 00398 * GUI thread (which would anyway require the use of 00399 * gdk_threads_enter()/gdk_threads_leave()), then the calling thread 00400 * must ensure that the main GUI thread does not destroy the relevant 00401 * tree view, and so the GtkTreeSelection object, from the beginning 00402 * of the 'if' test to the end of the 'if' block, or for the duration 00403 * of the try block. (This cannot be done just by incrementing the 00404 * reference count of the tree view or the tree selection in the 00405 * calling thread before the 'if' test or the try block is entered, 00406 * because by the time the reference is incremented and the weak 00407 * pointer tested, the tree view and tree selection may already be in 00408 * their dispose functions but the tree selection's dispose function 00409 * may not yet have reached the point of dispatching the callback 00410 * NULLing the weak pointer. As a general design issue, it is usually 00411 * best only to call GTK+ functions in one thread, and in order to 00412 * make that straightforward, this library contains a number of 00413 * classes and functions for inter-thread communication.) 00414 */ 00415 00416 struct GobjWeakHandleError: public std::exception { 00417 virtual const char* what() const throw() {return "GobjWeakHandleError\n";} 00418 }; 00419 00420 template <class T> class GobjWeakHandle { 00421 00422 T* obj_p; 00423 00424 public: 00425 00426 /** 00427 * This constructor does not throw. 00428 * @param ptr The object which the GobjWeakHandle is to track (if any). 00429 */ 00430 explicit GobjWeakHandle(T* ptr = 0) { 00431 obj_p = ptr; 00432 if (ptr) g_object_add_weak_pointer(G_OBJECT(ptr), 00433 (void**)&obj_p); 00434 } 00435 00436 /** 00437 * Causes the handle to cease to track its tracked object (if any). 00438 * If the argument passed is not NULL, the handle will track the new 00439 * object passed. This method does not throw. 00440 * @param ptr NULL (the default), or a new object to track. 00441 */ 00442 void reset(T* ptr = 0) { 00443 00444 if (obj_p) g_object_remove_weak_pointer(G_OBJECT(obj_p), 00445 (void**)&obj_p); 00446 obj_p = ptr; 00447 if (ptr) g_object_add_weak_pointer(G_OBJECT(ptr), 00448 (void**)&obj_p); 00449 } 00450 00451 /** 00452 * The copy constructor does not throw. It constructs a new weak 00453 * pointer tracking the same GObject as that tracked by the existing 00454 * weak pointer. 00455 * @param gobj The handle to be copied. 00456 */ 00457 GobjWeakHandle(const GobjWeakHandle& gobj) { 00458 obj_p = gobj.obj_p; 00459 if (obj_p) g_object_add_weak_pointer(G_OBJECT(obj_p), 00460 (void**)&obj_p); 00461 } 00462 00463 /** 00464 * This constructor constructs a weak pointer for a GObject managed 00465 * by a GobjHandle handle. It does not throw. 00466 * @param gobj The GobjHandle managing the GObject which the 00467 * GobjWeakHandle is to track. 00468 */ 00469 GobjWeakHandle(const GobjHandle<T>& gobj) { 00470 obj_p = gobj.get(); 00471 if (obj_p) g_object_add_weak_pointer(G_OBJECT(obj_p), 00472 (void**)&obj_p); 00473 } 00474 00475 /** 00476 * This method does not throw. It causes the handle to cease to 00477 * track its tracked object (if any), and begin tracking the same 00478 * GObject as that tracked by the assignor. This method does not 00479 * throw. 00480 * @param gobj The assignor. 00481 * @return The GobjWeakHandle object after assignment. 00482 */ 00483 GobjWeakHandle& operator=(const GobjWeakHandle& gobj) { 00484 // self assignment takes care of itself 00485 reset(gobj.obj_p); 00486 return *this; 00487 } 00488 00489 /** 00490 * This method does not throw. It causes the handle to cease to 00491 * track its tracked object (if any), and begin tracking the GObject 00492 * managed by the GobjHandle argument. This method does not throw. 00493 * @param gobj The assignor GobjHandle. 00494 * @return The GobjWeakHandle object after assignment. 00495 */ 00496 GobjWeakHandle& operator=(const GobjHandle<T>& gobj) { 00497 reset(gobj.get()); 00498 return *this; 00499 } 00500 00501 /** 00502 * This method does not throw. 00503 * @return True if the tracked GObject still exists, or false if it 00504 * does not or no GObject is being tracked. 00505 * @note The valid() method is a synonym for this method. 00506 */ 00507 operator bool() const {return obj_p;} 00508 00509 #ifndef DOXYGEN_PARSING 00510 /* 00511 * DEPRECATED: Do not use this method as it is only retained for 00512 * source compatibility. Its semantics are the wrong way around: 00513 * expired() returns true if the GObject still exists, instead of 00514 * false. Use operator bool() or the valid() method instead, which 00515 * have the correct semantics. This method does not throw. 00516 */ 00517 bool expired() const {return obj_p;} 00518 #endif 00519 00520 /** 00521 * This method does not throw. 00522 * @return True if the tracked GObject still exists, or false if it 00523 * does not or no GObject is being tracked. 00524 * @note operator bool() is a synonym for this method. 00525 * 00526 * Since 2.0.5 00527 */ 00528 bool valid() const {return obj_p;} 00529 00530 /** 00531 * This method does not throw. 00532 * @return A pointer to the tracked GObject. 00533 * @exception GobjWeakHandleError This method will throw 00534 * GobjWeakHandleError if the tracked object no longer exists or none 00535 * is being tracked. There is no need to check for this exception if 00536 * the status of the tracked object has been established with 00537 * operator bool() or valid(). 00538 */ 00539 T* get() const {if (!obj_p) throw GobjWeakHandleError(); return obj_p;} 00540 00541 /** 00542 * This method does not throw. 00543 * @return A reference to the tracked GObject. 00544 * @exception GobjWeakHandleError This method will throw 00545 * GobjWeakHandleError if the tracked object no longer exists or none 00546 * is being tracked. There is no need to check for this exception if 00547 * the status of the tracked object has been established with 00548 * operator bool() or valid(). 00549 */ 00550 T& operator*() const {if (!obj_p) throw GobjWeakHandleError(); return *obj_p;} 00551 00552 /** 00553 * This method does not throw. 00554 * @return A pointer to the tracked GObject. 00555 * @exception GobjWeakHandleError This method will throw 00556 * GobjWeakHandleError if the tracked object no longer exists or none 00557 * is being tracked. There is no need to check for this exception if 00558 * the status of the tracked object has been established with 00559 * operator bool() or valid(). 00560 */ 00561 T* operator->() const {if (!obj_p) throw GobjWeakHandleError(); return obj_p;} 00562 00563 /** 00564 * This method does not throw. 00565 * @return A pointer to the tracked GObject. 00566 * @exception GobjWeakHandleError This method will throw 00567 * GobjWeakHandleError if the tracked object no longer exists or none 00568 * is being tracked. There is no need to check for this exception if 00569 * the status of the tracked object has been established with 00570 * operator bool() or valid(). 00571 */ 00572 operator T*() const {if (!obj_p) throw GobjWeakHandleError(); return obj_p;} 00573 00574 /** 00575 * The destructor does not throw. 00576 */ 00577 ~GobjWeakHandle() {if (obj_p) g_object_remove_weak_pointer(G_OBJECT(obj_p), 00578 (void**)&obj_p);} 00579 }; 00580 00581 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING) 00582 00583 // we can use built-in operator == when comparing pointers referencing 00584 // different objects of the same type 00585 /** 00586 * @ingroup handles 00587 * 00588 * This comparison operator does not throw. It compares the addresses 00589 * of the managed objects. 00590 * 00591 * Since 2.0.0-rc2 00592 */ 00593 template <class T> 00594 bool operator==(const GobjHandle<T>& h1, const GobjHandle<T>& h2) { 00595 return (h1.get() == h2.get()); 00596 } 00597 00598 /** 00599 * @ingroup handles 00600 * 00601 * This comparison operator does not throw. It compares the addresses 00602 * of the managed objects. 00603 * 00604 * Since 2.0.0-rc2 00605 */ 00606 template <class T> 00607 bool operator!=(const GobjHandle<T>& h1, const GobjHandle<T>& h2) { 00608 return !(h1 == h2); 00609 } 00610 00611 // we must use std::less rather than the < built-in operator for 00612 // pointers to objects not within the same array or object: "For 00613 // templates greater, less, greater_equal, and less_equal, the 00614 // specializations for any pointer type yield a total order, even if 00615 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8). 00616 /** 00617 * @ingroup handles 00618 * 00619 * This comparison operator does not throw. It compares the addresses 00620 * of the managed objects. 00621 * 00622 * Since 2.0.0-rc2 00623 */ 00624 template <class T> 00625 bool operator<(const GobjHandle<T>& h1, const GobjHandle<T>& h2) { 00626 return std::less<T*>()(h1.get(), h2.get()); 00627 } 00628 00629 #endif // CGU_USE_SMART_PTR_COMPARISON 00630 00631 } // namespace Cgu 00632 00633 // doxygen produces long filenames that tar can't handle: 00634 // we have generic documentation for std::hash specialisations 00635 // in doxygen.main.in 00636 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING) 00637 /* This struct allows GobjHandle objects to be keys in unordered 00638 associative containers */ 00639 namespace std { 00640 template <class T> 00641 struct hash<Cgu::GobjHandle<T>> { 00642 typedef std::size_t result_type; 00643 typedef Cgu::GobjHandle<T> argument_type; 00644 result_type operator()(const argument_type& h) const { 00645 // this is fine: std::hash structs do not normally contain data and 00646 // std::hash<T*> certainly won't, so we don't have overhead constructing 00647 // std::hash<T*> on the fly 00648 return std::hash<T*>()(h.get()); 00649 } 00650 }; 00651 } // namespace std 00652 #endif // CGU_USE_SMART_PTR_COMPARISON 00653 00654 #endif