Alexandre Lision | ddd731e | 2014-01-31 11:50:08 -0500 | [diff] [blame] | 1 | // Copyright (C) 2006-2010 David Sugar, Tycho Softworks. |
| 2 | // |
| 3 | // This file is part of GNU uCommon C++. |
| 4 | // |
| 5 | // GNU uCommon C++ is free software: you can redistribute it and/or modify |
| 6 | // it under the terms of the GNU Lesser General Public License as published |
| 7 | // by the Free Software Foundation, either version 3 of the License, or |
| 8 | // (at your option) any later version. |
| 9 | // |
| 10 | // GNU uCommon C++ is distributed in the hope that it will be useful, |
| 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | // GNU Lesser General Public License for more details. |
| 14 | // |
| 15 | // You should have received a copy of the GNU Lesser General Public License |
| 16 | // along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>. |
| 17 | |
| 18 | /** |
| 19 | * A common object base class with auto-pointer support. |
| 20 | * A common object class is used which may be referenced counted and |
| 21 | * associated with a smart auto-pointer class. A lot of the things |
| 22 | * found here were inspired by working with Objective-C. Many of the |
| 23 | * classes are designed to offer automatic heap management through |
| 24 | * smart pointers and temporary objects controlled through the scope of |
| 25 | * the stack frame of method calls. |
| 26 | * @file ucommon/object.h |
| 27 | */ |
| 28 | |
| 29 | #ifndef _UCOMMON_OBJECT_H_ |
| 30 | #define _UCOMMON_OBJECT_H_ |
| 31 | |
| 32 | #ifndef _UCOMMON_CPR_H_ |
| 33 | #include <ucommon/cpr.h> |
| 34 | #endif |
| 35 | |
| 36 | #ifndef _UCOMMON_GENERICS_H_ |
| 37 | #include <ucommon/generics.h> |
| 38 | #endif |
| 39 | |
| 40 | #ifndef _UCOMMON_PROTOCOLS_H_ |
| 41 | #include <ucommon/protocols.h> |
| 42 | #endif |
| 43 | |
| 44 | #include <stdlib.h> |
| 45 | |
| 46 | NAMESPACE_UCOMMON |
| 47 | |
| 48 | /** |
| 49 | * A base class for reference counted objects. Reference counted objects |
| 50 | * keep track of how many objects refer to them and fall out of scope when |
| 51 | * they are no longer being referred to. This can be used to achieve |
| 52 | * automatic heap management when used in conjunction with smart pointers. |
| 53 | * @author David Sugar <dyfet@gnutelephony.org> |
| 54 | */ |
| 55 | class __EXPORT CountedObject : public ObjectProtocol |
| 56 | { |
| 57 | private: |
| 58 | volatile unsigned count; |
| 59 | |
| 60 | protected: |
| 61 | /** |
| 62 | * Construct a counted object, mark initially as unreferenced. |
| 63 | */ |
| 64 | CountedObject(); |
| 65 | |
| 66 | /** |
| 67 | * Construct a copy of a counted object. Our instance is not a |
| 68 | * reference to the original object but a duplicate, so we do not |
| 69 | * retain the original and we do reset our count to mark as |
| 70 | * initially unreferenced. |
| 71 | */ |
| 72 | CountedObject(const ObjectProtocol &ref); |
| 73 | |
| 74 | /** |
| 75 | * Dealloc object no longer referenced. The dealloc routine would commonly |
| 76 | * be used for a self delete to return the object back to a heap when |
| 77 | * it is no longer referenced. |
| 78 | */ |
| 79 | virtual void dealloc(void); |
| 80 | |
| 81 | /** |
| 82 | * Force reset of count. |
| 83 | */ |
| 84 | inline void reset(void) |
| 85 | {count = 0;} |
| 86 | |
| 87 | public: |
| 88 | /** |
| 89 | * Test if the object has copied references. This means that more than |
| 90 | * one object has a reference to our object. |
| 91 | * @return true if referenced by more than one object. |
| 92 | */ |
| 93 | inline bool is_copied(void) |
| 94 | {return count > 1;}; |
| 95 | |
| 96 | /** |
| 97 | * Test if the object has been referenced (retained) by anyone yet. |
| 98 | * @return true if retained. |
| 99 | */ |
| 100 | inline bool is_retained(void) |
| 101 | {return count > 0;}; |
| 102 | |
| 103 | /** |
| 104 | * Return the number of active references (retentions) to our object. |
| 105 | * @return number of references to our object. |
| 106 | */ |
| 107 | inline unsigned copied(void) |
| 108 | {return count;}; |
| 109 | |
| 110 | /** |
| 111 | * Increase reference count when retained. |
| 112 | */ |
| 113 | void retain(void); |
| 114 | |
| 115 | /** |
| 116 | * Decrease reference count when released. If no longer retained, then |
| 117 | * the object is dealloc'd. |
| 118 | */ |
| 119 | void release(void); |
| 120 | }; |
| 121 | |
| 122 | /** |
| 123 | * A general purpose smart pointer helper class. This is particularly |
| 124 | * useful in conjunction with reference counted objects which can be |
| 125 | * managed and automatically removed from the heap when they are no longer |
| 126 | * being referenced by a smart pointer. The smart pointer itself would |
| 127 | * normally be constructed and initialized as an auto variable in a method |
| 128 | * call, and will dereference the object when the pointer falls out of scope. |
| 129 | * This is actually a helper class for the typed pointer template. |
| 130 | * @author David Sugar <dyfet@gnutelephony.org> |
| 131 | */ |
| 132 | class __EXPORT auto_object |
| 133 | { |
| 134 | protected: |
| 135 | ObjectProtocol *object; |
| 136 | |
| 137 | auto_object(); |
| 138 | |
| 139 | public: |
| 140 | /** |
| 141 | * Construct an auto-pointer referencing an existing object. |
| 142 | * @param object we point to. |
| 143 | */ |
| 144 | auto_object(ObjectProtocol *object); |
| 145 | |
| 146 | /** |
| 147 | * Construct an auto-pointer as a copy of another pointer. The |
| 148 | * retention of the object being pointed to will be increased. |
| 149 | * @param pointer we are a copy of. |
| 150 | */ |
| 151 | auto_object(const auto_object &pointer); |
| 152 | |
| 153 | /** |
| 154 | * Delete auto pointer. When it falls out of scope, the retention |
| 155 | * of the object it references is reduced. If it falls to zero in |
| 156 | * a reference counted object, then the object is auto-deleted. |
| 157 | */ |
| 158 | ~auto_object(); |
| 159 | |
| 160 | /** |
| 161 | * Manually release the pointer. This reduces the retention level |
| 162 | * of the object and resets the pointer to point to nobody. |
| 163 | */ |
| 164 | void release(void); |
| 165 | |
| 166 | /** |
| 167 | * Test if the pointer is not set. |
| 168 | * @return true if the pointer is not referencing anything. |
| 169 | */ |
| 170 | bool operator!() const; |
| 171 | |
| 172 | /** |
| 173 | * Test if the pointer is referencing an object. |
| 174 | * @return true if the pointer is currently referencing an object. |
| 175 | */ |
| 176 | operator bool() const; |
| 177 | |
| 178 | /** |
| 179 | * test if the object being referenced is the same as the object we specify. |
| 180 | * @param object we compare to. |
| 181 | * @return true if this is the object our pointer references. |
| 182 | */ |
| 183 | bool operator==(ObjectProtocol *object) const; |
| 184 | |
| 185 | /** |
| 186 | * test if the object being referenced is not the same as the object we specify. |
| 187 | * @param object we compare to. |
| 188 | * @return true if this is not the object our pointer references. |
| 189 | */ |
| 190 | bool operator!=(ObjectProtocol *object) const; |
| 191 | |
| 192 | /** |
| 193 | * Set our pointer to a specific object. If the pointer currently |
| 194 | * references another object, that object is released. The pointer |
| 195 | * references our new object and that new object is retained. |
| 196 | * @param object to assign to. |
| 197 | */ |
| 198 | void operator=(ObjectProtocol *object); |
| 199 | }; |
| 200 | |
| 201 | /** |
| 202 | * A sparse array of managed objects. This might be used as a simple |
| 203 | * array class for reference counted objects. This class assumes that |
| 204 | * objects in the array exist when assigned, and that gaps in the array |
| 205 | * are positions that do not reference any object. Objects are automatically |
| 206 | * created (create on access/modify when an array position is referenced |
| 207 | * for the first time. This is an abstract class because it is a type |
| 208 | * factory for objects who's derived class form constructor is not known |
| 209 | * in advance and is a helper class for the sarray template. |
| 210 | * @author David Sugar <dyfet@gnutelephony.org> |
| 211 | */ |
| 212 | class __EXPORT SparseObjects |
| 213 | { |
| 214 | private: |
| 215 | ObjectProtocol **vector; |
| 216 | unsigned max; |
| 217 | |
| 218 | protected: |
| 219 | /** |
| 220 | * Object factory for creating members of the spare array when they |
| 221 | * are initially requested. |
| 222 | * @return new object. |
| 223 | */ |
| 224 | virtual ObjectProtocol *create(void) = 0; |
| 225 | |
| 226 | /** |
| 227 | * Purge the array by deleting all created objects. |
| 228 | */ |
| 229 | void purge(void); |
| 230 | |
| 231 | virtual ObjectProtocol *invalid(void) const; |
| 232 | |
| 233 | /** |
| 234 | * Get (reference) an object at a specified offset in the array. |
| 235 | * @param offset in array. |
| 236 | * @return new or existing object. |
| 237 | */ |
| 238 | ObjectProtocol *get(unsigned offset); |
| 239 | |
| 240 | /** |
| 241 | * Create a sparse array of known size. No member objects are |
| 242 | * created until they are referenced. |
| 243 | * @param size of array. |
| 244 | */ |
| 245 | SparseObjects(unsigned size); |
| 246 | |
| 247 | /** |
| 248 | * Destroy sparse array and delete all generated objects. |
| 249 | */ |
| 250 | virtual ~SparseObjects(); |
| 251 | |
| 252 | public: |
| 253 | /** |
| 254 | * Get count of array elements. |
| 255 | * @return array elements. |
| 256 | */ |
| 257 | unsigned count(void); |
| 258 | }; |
| 259 | |
| 260 | /** |
| 261 | * Generate a typed sparse managed object array. Members in the array |
| 262 | * are created when they are first referenced. The types for objects |
| 263 | * that are generated by sarray must have Object as a base class. Managed |
| 264 | * sparse arrays differ from standard arrays in that the member elements |
| 265 | * are not allocated from the heap when the array is created, but rather |
| 266 | * as they are needed. |
| 267 | * @author David Sugar <dyfet@gnutelephony.org> |
| 268 | */ |
| 269 | template <class T> |
| 270 | class sarray : public SparseObjects |
| 271 | { |
| 272 | public: |
| 273 | /** |
| 274 | * Generate a sparse typed array of specified size. |
| 275 | * @param size of array to create. |
| 276 | */ |
| 277 | inline sarray(unsigned size) : SparseObjects(size) {}; |
| 278 | |
| 279 | /** |
| 280 | * Get typed member of array. If the object does not exist, it is |
| 281 | * created. |
| 282 | * @param offset in array for object. |
| 283 | * @return pointer to typed object. |
| 284 | */ |
| 285 | inline T *get(unsigned offset) |
| 286 | {return static_cast<T*>(SparseObjects::get(offset));} |
| 287 | |
| 288 | /** |
| 289 | * Array operation to access member object. If the object does not |
| 290 | * exist, it is created. |
| 291 | * @param offset in array for object. |
| 292 | * @return pointer to typed object. |
| 293 | */ |
| 294 | inline T& operator[](unsigned offset) |
| 295 | {return get(offset);}; |
| 296 | |
| 297 | inline const T* at(unsigned offset) |
| 298 | {return static_cast<const T&>(SparseObjects::get(offset));} |
| 299 | |
| 300 | private: |
| 301 | __LOCAL ObjectProtocol *create(void) |
| 302 | {return new T;}; |
| 303 | }; |
| 304 | |
| 305 | /** |
| 306 | * Template for embedding a data structure into a reference counted object. |
| 307 | * This is a convenient means to create reference counted heap managed data |
| 308 | * structure. This template can be used for embedding data into other kinds |
| 309 | * of managed object classes in addition to reference counting. For example, |
| 310 | * it can be used to embed a data structure into a linked list, as shown in |
| 311 | * the linked_value template. |
| 312 | * @author David Sugar <dyfet@gnutelephony.org> |
| 313 | */ |
| 314 | template <typename T, class O = CountedObject> |
| 315 | class object_value : public O |
| 316 | { |
| 317 | protected: |
| 318 | /** |
| 319 | * Assign our value from a typed data object. This is a helper method. |
| 320 | * @param object to assign our value from. |
| 321 | */ |
| 322 | inline void set(const T& object) |
| 323 | {value = object;}; |
| 324 | |
| 325 | public: |
| 326 | T value; /**< Embedded data value */ |
| 327 | |
| 328 | /** |
| 329 | * Construct composite value object. |
| 330 | */ |
| 331 | inline object_value() : O() {}; |
| 332 | |
| 333 | /** |
| 334 | * Construct composite value object and assign from existing data value. |
| 335 | * @param existing typed value to assign. |
| 336 | */ |
| 337 | inline object_value(T& existing) : O() |
| 338 | {value = existing;}; |
| 339 | |
| 340 | /** |
| 341 | * Pointer reference to embedded data value. |
| 342 | * @return embedded value. |
| 343 | */ |
| 344 | inline T& operator*() |
| 345 | {return value;}; |
| 346 | |
| 347 | /** |
| 348 | * Assign embedded data value. |
| 349 | * @param data value to assign. |
| 350 | */ |
| 351 | inline void operator=(const T& data) |
| 352 | {value = data;}; |
| 353 | |
| 354 | /** |
| 355 | * Retrieve data value by casting reference. |
| 356 | * @return embedded value. |
| 357 | */ |
| 358 | inline operator T&() |
| 359 | {return value;}; |
| 360 | |
| 361 | inline T& operator()() |
| 362 | {return value;}; |
| 363 | |
| 364 | /** |
| 365 | * Set data value by expression reference. |
| 366 | * @param data value to assign. |
| 367 | */ |
| 368 | inline void operator()(T& data) |
| 369 | {value = data;}; |
| 370 | }; |
| 371 | |
| 372 | /** |
| 373 | * Typed smart pointer class. This is used to manage references to |
| 374 | * a specific typed object on the heap that is derived from the base Object |
| 375 | * class. This is most commonly used to manage references to reference |
| 376 | * counted heap objects so their heap usage can be auto-managed while there |
| 377 | * is active references to such objects. Pointers are usually created on |
| 378 | * the stack frame and used to reference an object during the life of a |
| 379 | * member function. They can be created in other objects that live on the |
| 380 | * heap and can be used to maintain active references so long as the object |
| 381 | * they are contained in remains in scope as well. |
| 382 | * @author David Sugar <dyfet@gnutelephony.org> |
| 383 | */ |
| 384 | template <class T, class P = auto_object> |
| 385 | class object_pointer : public P |
| 386 | { |
| 387 | public: |
| 388 | /** |
| 389 | * Create a pointer with no reference. |
| 390 | */ |
| 391 | inline object_pointer() : P() {}; |
| 392 | |
| 393 | /** |
| 394 | * Create a pointer with a reference to a heap object. |
| 395 | * @param object we are referencing. |
| 396 | */ |
| 397 | inline object_pointer(T* object) : P(object) {}; |
| 398 | |
| 399 | /** |
| 400 | * Reference object we are pointing to through pointer indirection. |
| 401 | * @return pointer to object we are pointing to. |
| 402 | */ |
| 403 | inline T* operator*() const |
| 404 | {return static_cast<T*>(P::object);}; |
| 405 | |
| 406 | /** |
| 407 | * Reference object we are pointing to through function reference. |
| 408 | * @return object we are pointing to. |
| 409 | */ |
| 410 | inline T& operator()() const |
| 411 | {return *(static_cast<T*>(P::object));}; |
| 412 | |
| 413 | /** |
| 414 | * Reference member of object we are pointing to. |
| 415 | * @return reference to member of pointed object. |
| 416 | */ |
| 417 | inline T* operator->() const |
| 418 | {return static_cast<T*>(P::object);}; |
| 419 | |
| 420 | /** |
| 421 | * Get pointer to object. |
| 422 | * @return pointer or NULL if we are not referencing an object. |
| 423 | */ |
| 424 | inline T* get(void) const |
| 425 | {return static_cast<T*>(P::object);}; |
| 426 | |
| 427 | /** |
| 428 | * Iterate our pointer if we reference an array on the heap. |
| 429 | * @return next object in array. |
| 430 | */ |
| 431 | inline T* operator++() |
| 432 | {P::operator++(); return get();}; |
| 433 | |
| 434 | /** |
| 435 | * Iterate our pointer if we reference an array on the heap. |
| 436 | * @return previous object in array. |
| 437 | */ |
| 438 | inline void operator--() |
| 439 | {P::operator--(); return get();}; |
| 440 | |
| 441 | /** |
| 442 | * Perform assignment operator to existing object. |
| 443 | * @param typed object to assign. |
| 444 | */ |
| 445 | inline void operator=(T *typed) |
| 446 | {P::operator=((ObjectProtocol *)typed);}; |
| 447 | |
| 448 | /** |
| 449 | * See if pointer is set. |
| 450 | */ |
| 451 | inline operator bool() |
| 452 | {return P::object != NULL;}; |
| 453 | |
| 454 | /** |
| 455 | * See if pointer is not set. |
| 456 | */ |
| 457 | inline bool operator!() |
| 458 | {return P::object == NULL;}; |
| 459 | }; |
| 460 | |
| 461 | /** |
| 462 | * Convenience function to access object retention. |
| 463 | * @param object we are retaining. |
| 464 | */ |
| 465 | inline void retain(ObjectProtocol *object) |
| 466 | {object->retain();} |
| 467 | |
| 468 | /** |
| 469 | * Convenience function to access object release. |
| 470 | * @param object we are releasing. |
| 471 | */ |
| 472 | inline void release(ObjectProtocol *object) |
| 473 | {object->release();} |
| 474 | |
| 475 | /** |
| 476 | * Convenience function to access object copy. |
| 477 | * @param object we are copying. |
| 478 | */ |
| 479 | inline ObjectProtocol *copy(ObjectProtocol *object) |
| 480 | {return object->copy();} |
| 481 | |
| 482 | END_NAMESPACE |
| 483 | |
| 484 | #endif |