Object Domain

Files CCore/inc/ObjectDomain.h CCore/src/ObjectDomain.cpp

ObjectDomain is an arbitrary object collection with Garbage Collection capabilities. It means the domain implements the garbage collection algorithm, during the garbage collection all unreferenced objects are destroyed. Objects, included in the domain, must participate in GC operations. It is implemented throw two special object methods.


class SomeClass
 {
   IntObjPtr<Type1> ptr;
   WeakObjPtr<Type2> weak_ptr;
   IntDelObjPtr<Type3> del_ptr;

  public:

   template <class Keeper>
   void keepAlive(Keeper keeper)
    {
     keeper(ptr);
     keeper(del_ptr);
    }
   
   template <class Breaker>
   void breakWeak(Breaker breaker)
    {
     breaker(weak_ptr);
    }
 };

There are 3 special smart pointer classes to support object referencing. When a class member reference another object being governed by the domain, it must be one of these three types.

IntObjPtr<Type> is used to reference another domain object by class members. If this pointer is not null, then the correspondent object is kept alive at least the referencing object is alive. So you may safely assume the pointer is valid. You must use this pointer in the keepAlive() method as the argument of the keeper call.

IntDelObjPtr<Type> is similar to the IntObjPtr<Type>, but is has the method destroy(). This method destroys the object being referenced, so other such pointers referencing the same object are nullified. Using this kind of pointer you must always check the pointer is not null, before using the object being referenced.

WeakObjPtr<Type> is a weak pointer. It does not keep the object being referenced alive. If this object is destroyed, the pointer is nullified. You must use this pointer in the breakWeak() method as the argument of the breaker call.

If one of the keepAlive() or keepAlive() method has an empty body, you may skip its definition entirely.

If you reference a domain object not from a member, but from a local or global variable, you must use another smart pointers:


ExtObjPtr<Type1> ptr;

ExtDelObjPtr<Type2> del_ptr;

You may freely cast between IntObjPtr<Type>, WeakObjPtr<Type> and ExtObjPtr<Type>.

You may also freely cast between IntDelObjPtr<Type> and ExtDelObjPtr<Type>.

ObjectDomain

The class ObjectDomain is essentially single-threaded. You may use it as is, but it's likely, you would derive another class from it to serve as an object domain. It is convenient to create a domain object and store a global pointer to it for a further use.


class ObjectDomain : NoCopy
 {
   ....
  
  private:
   
   virtual void * try_alloc(ulen len);
  
   virtual void free(void *mem);

  protected:
   
   void cleanup(); // must be called in the destructor of a derived class
  
  public:
  
   // constructors
  
   explicit ObjectDomain(ulen max_total_len);
   
   ~ObjectDomain();
   
   void collect();
   
   // props
   
   ulen getObjectCount() const;
   
   ulen getTotalLen() const;
   
   ulen getMaxTotalLen() const;
   
   ulen getAvail() const;
 };

try_alloc() and free() may be overloaded in a derived class to implement heap operations.

cleanup() must be called in the destructor of a derived class.

The constructor argument max_total_len is a total memory allocation limit for domain objects.

collect() performs the garbage collection.

getObjectCount() returns the number of domain objects.

getTotalLen() returns the total memory, occupied by domain objects.

getMaxTotalLen() is a total memory allocation limit for domain objects.

getAvail() is remaining available memory.

Below is an example of the ObjectDomain usage.


/* class TestDomain */

class TestDomain : public ObjectDomain
 {
   SpaceHeap heap;
   
  private: 
   
   virtual void * try_alloc(ulen len) { return heap.alloc(len); }
  
   virtual void free(void *mem) { heap.free(mem); }
   
  public:
  
   explicit TestDomain(ulen max_total_mem) : ObjectDomain(max_total_mem),heap(2*max_total_mem) {}
   
   ~TestDomain() { cleanup(); }
 };

/* global Domain */

static ObjectDomain * Domain=0;

....

int main()
 {
  TestDomain domain(10_MByte);
  
  Domain=&domain;

  ....
  
  return 0;
 }

Object pointers

You create and manipulate domain objects via a set of smart pointers.

Each smart pointer has the default constructor and the NothingType constructor, both creates a null pointer.

Each smart pointer has also the method nullify() to set the pointer to the null state.

Each smart pointer has a generic constructor to create a domain object. The pointer will reference the created object.


template <class ... SS>
explicit SomePtr(ObjectDomain *domain,SS && ... ss);

The first argument is the ObjectDomain pointer. Other arguments are used to create the object.

Each smart pointer implements the Object Pointer Interface.

Each smart pointer is efficiently copyable. For some the swap/move operations are implemented for the sake of efficiency.

ExtObjPtr

This smart pointer should be used to reference domain objects by local or global variables. It keeps the object being referenced alive. So you must destroy or nullify all such objects before the ObjectDomain is destroyed. ExtObjPtr<T>, in fact, is the alias of the ObjectDomain::ExtPtr<T>.


template <class T>
class ObjectDomain::ExtPtr
 {
   ....

  public:
   
   // constructors
  
   ExtPtr() noexcept;
   
   explicit ExtPtr(NothingType);
   
   ExtPtr(const IntPtr<T> &obj); 
   
   ExtPtr(const WeakPtr<T> &obj); 
   
   template <class ... SS>
   explicit ExtPtr(ObjectDomain *domain,SS && ... ss);
   
   ~ExtPtr();
   
   void nullify(); 

   // copying
   
   ExtPtr(const ExtPtr<T> &obj); 
   
   ExtPtr<T> & operator = (const ExtPtr<T> &obj);
   
   // object ptr
   
   void * operator + () const;
   
   bool operator ! () const;
  
   T * getPtr() const;
   
   T & operator * () const;
   
   T * operator -> () const;
   
   ulen getExtRefs() const;
   
   // swap/move objects
   
   void objSwap(ExtPtr<T> &obj);
   
   explicit ExtPtr(ToMoveCtor<ExtPtr<T> > obj);
 };

ExtObjPtr<T> is implicitly convertible from the IntObjPtr<T> and WeakObjPtr<T>.

getExtRefs() returns the external reference counter. The pointer must be non-null.

IntObjPtr

This smart pointer should be used to reference domain objects by members of another domain objects. It keeps the object being referenced alive. If a domain object contains members of this type, it must define the method keepAlive() and use these pointers as arguments of keeper calls inside this method. IntObjPtr<T>, in fact, is the alias of the ObjectDomain::IntPtr<T>.


template <class T> 
class ObjectDomain::IntPtr // default copying
 {
   ....

  public:
  
   // constructors
 
   IntPtr() noexcept;
  
   explicit IntPtr(NothingType);
   
   IntPtr(const ExtPtr<T> &obj);
  
   IntPtr(const WeakPtr<T> &obj);
   
   template <class ... SS>
   explicit IntPtr(ObjectDomain *domain,SS && ... ss);
  
   void nullify();
   
   // object ptr
   
   void * operator + () const;
   
   bool operator ! () const;
  
   T * getPtr() const;
   
   T & operator * () const;
   
   T * operator -> () const;
   
   ulen getExtRefs() const;
 };

IntObjPtr<T> is implicitly convertible from the ExtObjPtr<T> and WeakObjPtr<T>.

getExtRefs() returns the external reference counter. The pointer must be non-null.

WeakObjPtr

This smart pointer should be used to reference domain objects by members of another domain objects. It does not keep the object being referenced alive. So the object may be destroyed and if this happens the weak pointer is set to null. If a domain object contains members of this type, it must define the method breakWeak() and use these pointers as arguments of breaker calls inside this method. WeakObjPtr<T>, in fact, is the alias of the ObjectDomain::WeakPtr<T>.


template <class T>
class ObjectDomain::WeakPtr // default copying
 {
   ....

  public:
  
   // constructors
 
   WeakPtr() noexcept;
  
   explicit WeakPtr(NothingType);
   
   WeakPtr(const ExtPtr<T> &obj);
  
   WeakPtr(const IntPtr<T> &obj);
   
   template <class ... SS>
   explicit WeakPtr(ObjectDomain *domain,SS && ... ss);
  
   void nullify();
   
   // object ptr
   
   void * operator + () const;
   
   bool operator ! () const;
  
   T * getPtr() const;
   
   T & operator * () const;
   
   T * operator -> () const;
   
   ulen getExtRefs() const;
 };

WeakObjPtr<T> is implicitly convertible from the ExtObjPtr<T> and IntObjPtr<T>.

getExtRefs() returns the external reference counter. The pointer must be non-null.

ExtDelObjPtr

This smart pointer should be used to reference domain objects by local or global variables. It keeps the object being referenced alive. So you must destroy or nullify all such objects before the ObjectDomain is destroyed. The difference from the ExtObjPtr<T> is this pointer supports the manual object destruction via the method destroy().


template <class T>
class ExtDelObjPtr
 {
   ....

  public: 
   
   // constructors
   
   ExtDelObjPtr() noexcept;
   
   ExtDelObjPtr(NothingType);
   
   ExtDelObjPtr(const IntDelObjPtr<T> &obj);
   
   template <class ... SS>
   ExtDelObjPtr(ObjectDomain *domain,SS && ... ss);
   
   ~ExtDelObjPtr();
   
   void nullify();
   
   // object ptr
   
   void * operator + () const;
   
   bool operator ! () const;
  
   T * getPtr() const;
   
   T & operator * () const;
   
   T * operator -> () const;
   
   // destroy
   
   bool destroy();
 };

ExtDelObjPtr<T> is implicitly convertible from the IntDelObjPtr<T>.

destroy() destroys the object and nullifies the pointer. This is not possible, if there are other external references to this object, in this case the method simply returns false. Internal pointers to this object, if any, are nullified.

IntDelObjPtr

This smart pointer should be used to reference domain objects by members of another domain objects. It keeps the object being referenced alive, unless somebody destroys it manually. If a domain object contains members of this type, it must define the method keepAlive() and use these pointers as arguments of keeper calls inside this method. The difference from the IntObjPtr<T> is this pointer supports the manual object destruction via the method destroy().


template <class T>
class IntDelObjPtr
 {
   ....

  public: 
   
   // constructors
   
   IntDelObjPtr() noexcept;
   
   IntDelObjPtr(NothingType);
   
   IntDelObjPtr(const ExtDelObjPtr<T> &obj);
   
   template <class ... SS>
   IntDelObjPtr(ObjectDomain *domain,SS && ... ss);
   
   void nullify();
   
   // object ptr
   
   void * operator + () const;
   
   bool operator ! () const;
  
   T * getPtr() const;
   
   T & operator * () const;
   
   T * operator -> () const;
   
   // destroy
   
   bool destroy();
 };

IntDelObjPtr<T> is implicitly convertible from the ExtDelObjPtr<T>.

destroy() destroys the object and nullifies the pointer. This is not possible, if there are some external references to this object, in this case the method simply returns false. Internal pointers to this object, if any, are nullified.