blob: 6bbed7125d5e0b6311ff051aeb3c2029890196a1 [file] [log] [blame]
// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
//
// This file is part of GNU uCommon C++.
//
// GNU uCommon C++ is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU uCommon C++ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
/**
* A common object base class with auto-pointer support.
* A common object class is used which may be referenced counted and
* associated with a smart auto-pointer class. A lot of the things
* found here were inspired by working with Objective-C. Many of the
* classes are designed to offer automatic heap management through
* smart pointers and temporary objects controlled through the scope of
* the stack frame of method calls.
* @file ucommon/object.h
*/
#ifndef _UCOMMON_OBJECT_H_
#define _UCOMMON_OBJECT_H_
#ifndef _UCOMMON_CPR_H_
#include <ucommon/cpr.h>
#endif
#ifndef _UCOMMON_GENERICS_H_
#include <ucommon/generics.h>
#endif
#ifndef _UCOMMON_PROTOCOLS_H_
#include <ucommon/protocols.h>
#endif
#include <stdlib.h>
NAMESPACE_UCOMMON
/**
* A base class for reference counted objects. Reference counted objects
* keep track of how many objects refer to them and fall out of scope when
* they are no longer being referred to. This can be used to achieve
* automatic heap management when used in conjunction with smart pointers.
* @author David Sugar <dyfet@gnutelephony.org>
*/
class __EXPORT CountedObject : public ObjectProtocol
{
private:
volatile unsigned count;
protected:
/**
* Construct a counted object, mark initially as unreferenced.
*/
CountedObject();
/**
* Construct a copy of a counted object. Our instance is not a
* reference to the original object but a duplicate, so we do not
* retain the original and we do reset our count to mark as
* initially unreferenced.
*/
CountedObject(const ObjectProtocol &ref);
/**
* Dealloc object no longer referenced. The dealloc routine would commonly
* be used for a self delete to return the object back to a heap when
* it is no longer referenced.
*/
virtual void dealloc(void);
/**
* Force reset of count.
*/
inline void reset(void)
{count = 0;}
public:
/**
* Test if the object has copied references. This means that more than
* one object has a reference to our object.
* @return true if referenced by more than one object.
*/
inline bool is_copied(void)
{return count > 1;};
/**
* Test if the object has been referenced (retained) by anyone yet.
* @return true if retained.
*/
inline bool is_retained(void)
{return count > 0;};
/**
* Return the number of active references (retentions) to our object.
* @return number of references to our object.
*/
inline unsigned copied(void)
{return count;};
/**
* Increase reference count when retained.
*/
void retain(void);
/**
* Decrease reference count when released. If no longer retained, then
* the object is dealloc'd.
*/
void release(void);
};
/**
* A general purpose smart pointer helper class. This is particularly
* useful in conjunction with reference counted objects which can be
* managed and automatically removed from the heap when they are no longer
* being referenced by a smart pointer. The smart pointer itself would
* normally be constructed and initialized as an auto variable in a method
* call, and will dereference the object when the pointer falls out of scope.
* This is actually a helper class for the typed pointer template.
* @author David Sugar <dyfet@gnutelephony.org>
*/
class __EXPORT auto_object
{
protected:
ObjectProtocol *object;
auto_object();
public:
/**
* Construct an auto-pointer referencing an existing object.
* @param object we point to.
*/
auto_object(ObjectProtocol *object);
/**
* Construct an auto-pointer as a copy of another pointer. The
* retention of the object being pointed to will be increased.
* @param pointer we are a copy of.
*/
auto_object(const auto_object &pointer);
/**
* Delete auto pointer. When it falls out of scope, the retention
* of the object it references is reduced. If it falls to zero in
* a reference counted object, then the object is auto-deleted.
*/
~auto_object();
/**
* Manually release the pointer. This reduces the retention level
* of the object and resets the pointer to point to nobody.
*/
void release(void);
/**
* Test if the pointer is not set.
* @return true if the pointer is not referencing anything.
*/
bool operator!() const;
/**
* Test if the pointer is referencing an object.
* @return true if the pointer is currently referencing an object.
*/
operator bool() const;
/**
* test if the object being referenced is the same as the object we specify.
* @param object we compare to.
* @return true if this is the object our pointer references.
*/
bool operator==(ObjectProtocol *object) const;
/**
* test if the object being referenced is not the same as the object we specify.
* @param object we compare to.
* @return true if this is not the object our pointer references.
*/
bool operator!=(ObjectProtocol *object) const;
/**
* Set our pointer to a specific object. If the pointer currently
* references another object, that object is released. The pointer
* references our new object and that new object is retained.
* @param object to assign to.
*/
void operator=(ObjectProtocol *object);
};
/**
* A sparse array of managed objects. This might be used as a simple
* array class for reference counted objects. This class assumes that
* objects in the array exist when assigned, and that gaps in the array
* are positions that do not reference any object. Objects are automatically
* created (create on access/modify when an array position is referenced
* for the first time. This is an abstract class because it is a type
* factory for objects who's derived class form constructor is not known
* in advance and is a helper class for the sarray template.
* @author David Sugar <dyfet@gnutelephony.org>
*/
class __EXPORT SparseObjects
{
private:
ObjectProtocol **vector;
unsigned max;
protected:
/**
* Object factory for creating members of the spare array when they
* are initially requested.
* @return new object.
*/
virtual ObjectProtocol *create(void) = 0;
/**
* Purge the array by deleting all created objects.
*/
void purge(void);
virtual ObjectProtocol *invalid(void) const;
/**
* Get (reference) an object at a specified offset in the array.
* @param offset in array.
* @return new or existing object.
*/
ObjectProtocol *get(unsigned offset);
/**
* Create a sparse array of known size. No member objects are
* created until they are referenced.
* @param size of array.
*/
SparseObjects(unsigned size);
/**
* Destroy sparse array and delete all generated objects.
*/
virtual ~SparseObjects();
public:
/**
* Get count of array elements.
* @return array elements.
*/
unsigned count(void);
};
/**
* Generate a typed sparse managed object array. Members in the array
* are created when they are first referenced. The types for objects
* that are generated by sarray must have Object as a base class. Managed
* sparse arrays differ from standard arrays in that the member elements
* are not allocated from the heap when the array is created, but rather
* as they are needed.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template <class T>
class sarray : public SparseObjects
{
public:
/**
* Generate a sparse typed array of specified size.
* @param size of array to create.
*/
inline sarray(unsigned size) : SparseObjects(size) {};
/**
* Get typed member of array. If the object does not exist, it is
* created.
* @param offset in array for object.
* @return pointer to typed object.
*/
inline T *get(unsigned offset)
{return static_cast<T*>(SparseObjects::get(offset));}
/**
* Array operation to access member object. If the object does not
* exist, it is created.
* @param offset in array for object.
* @return pointer to typed object.
*/
inline T& operator[](unsigned offset)
{return get(offset);};
inline const T* at(unsigned offset)
{return static_cast<const T&>(SparseObjects::get(offset));}
private:
__LOCAL ObjectProtocol *create(void)
{return new T;};
};
/**
* Template for embedding a data structure into a reference counted object.
* This is a convenient means to create reference counted heap managed data
* structure. This template can be used for embedding data into other kinds
* of managed object classes in addition to reference counting. For example,
* it can be used to embed a data structure into a linked list, as shown in
* the linked_value template.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template <typename T, class O = CountedObject>
class object_value : public O
{
protected:
/**
* Assign our value from a typed data object. This is a helper method.
* @param object to assign our value from.
*/
inline void set(const T& object)
{value = object;};
public:
T value; /**< Embedded data value */
/**
* Construct composite value object.
*/
inline object_value() : O() {};
/**
* Construct composite value object and assign from existing data value.
* @param existing typed value to assign.
*/
inline object_value(T& existing) : O()
{value = existing;};
/**
* Pointer reference to embedded data value.
* @return embedded value.
*/
inline T& operator*()
{return value;};
/**
* Assign embedded data value.
* @param data value to assign.
*/
inline void operator=(const T& data)
{value = data;};
/**
* Retrieve data value by casting reference.
* @return embedded value.
*/
inline operator T&()
{return value;};
inline T& operator()()
{return value;};
/**
* Set data value by expression reference.
* @param data value to assign.
*/
inline void operator()(T& data)
{value = data;};
};
/**
* Typed smart pointer class. This is used to manage references to
* a specific typed object on the heap that is derived from the base Object
* class. This is most commonly used to manage references to reference
* counted heap objects so their heap usage can be auto-managed while there
* is active references to such objects. Pointers are usually created on
* the stack frame and used to reference an object during the life of a
* member function. They can be created in other objects that live on the
* heap and can be used to maintain active references so long as the object
* they are contained in remains in scope as well.
* @author David Sugar <dyfet@gnutelephony.org>
*/
template <class T, class P = auto_object>
class object_pointer : public P
{
public:
/**
* Create a pointer with no reference.
*/
inline object_pointer() : P() {};
/**
* Create a pointer with a reference to a heap object.
* @param object we are referencing.
*/
inline object_pointer(T* object) : P(object) {};
/**
* Reference object we are pointing to through pointer indirection.
* @return pointer to object we are pointing to.
*/
inline T* operator*() const
{return static_cast<T*>(P::object);};
/**
* Reference object we are pointing to through function reference.
* @return object we are pointing to.
*/
inline T& operator()() const
{return *(static_cast<T*>(P::object));};
/**
* Reference member of object we are pointing to.
* @return reference to member of pointed object.
*/
inline T* operator->() const
{return static_cast<T*>(P::object);};
/**
* Get pointer to object.
* @return pointer or NULL if we are not referencing an object.
*/
inline T* get(void) const
{return static_cast<T*>(P::object);};
/**
* Iterate our pointer if we reference an array on the heap.
* @return next object in array.
*/
inline T* operator++()
{P::operator++(); return get();};
/**
* Iterate our pointer if we reference an array on the heap.
* @return previous object in array.
*/
inline void operator--()
{P::operator--(); return get();};
/**
* Perform assignment operator to existing object.
* @param typed object to assign.
*/
inline void operator=(T *typed)
{P::operator=((ObjectProtocol *)typed);};
/**
* See if pointer is set.
*/
inline operator bool()
{return P::object != NULL;};
/**
* See if pointer is not set.
*/
inline bool operator!()
{return P::object == NULL;};
};
/**
* Convenience function to access object retention.
* @param object we are retaining.
*/
inline void retain(ObjectProtocol *object)
{object->retain();}
/**
* Convenience function to access object release.
* @param object we are releasing.
*/
inline void release(ObjectProtocol *object)
{object->release();}
/**
* Convenience function to access object copy.
* @param object we are copying.
*/
inline ObjectProtocol *copy(ObjectProtocol *object)
{return object->copy();}
END_NAMESPACE
#endif