#ifndef ALREADY_INCLUDED_2006_LIBD_PTR_HH
#define ALREADY_INCLUDED_2006_LIBD_PTR_HH
namespace dmp
{
   ///
   /// X has to subclass Single so that it has a property called
   /// _ref_count.
   ///
   /// Generally ptr appears without trailing * so that ptr's are deleted
   /// with the enclosing object...  with the exception for Arrays,
   /// but even they are deleted with the ~Array
   ///
   /// sizeof(ptr) == 4 bytes (therefore it fits into a register)
   ///
   /// assumes X class has
   ///
   /// (1) ~X()
   /// (2) _ref_count property
   ///
   /// uses X of ptr template should privately inherit from Single,
   /// declare ptr<X> as a friend of the class and declare ~X() to be
   /// private.
   ///
   template<class X>
   final class ptr
   {
   private:
      X* inner_ptr;
public:
      ptr()
      {
         inner_ptr = null;
      }
ptr(const ptr& p)
      {
         ASSERT(&p != null);
         inner_ptr = p.inner_ptr;
         if (inner_ptr != null)
         {
            inner_ptr->_ref_count++;
         }
      }
ptr& operator = (const ptr& p)
      {
         ASSERT(this != null);
         ASSERT(&p != null);
         //if (p.inner_ptr != null) // protect against s = s
         if (p != null) // protect against s = s
         {
            p.inner_ptr->_ref_count++;
         }
         if (inner_ptr != null)
         {
            assert(inner_ptr->_ref_count > 0); // protect against double deletions
            inner_ptr->_ref_count--;
            if (inner_ptr->_ref_count == 0)
            {
               inner_ptr->_ref_count = 1; // protect against internal deletions
               delete inner_ptr;
            }
         }
         if (p == null)
         {
            inner_ptr = null;
         }
         else
         {
            inner_ptr = p.inner_ptr;
         }
         return *this;
      }
~ptr()
      {
         ASSERT(this != null);
         ///
         /// NOTE: bugfix for davins-allegro-random-midi-player.ch global delete of ptr<List<String>>
         ///
#ifdef ALLEGRO_ONLINE
         if (!allegro_on)
         {
            return;
         }
#endif /* ALLEGRO_ONLINE */
         ASSERT(this != null);
         if (inner_ptr != null)
         {
            assert(inner_ptr->_ref_count > 0); // protect against double deletions
            inner_ptr->_ref_count--;
            if (inner_ptr->_ref_count == 0)
            {
               inner_ptr->_ref_count = 1; // protect against internal deletions
               delete inner_ptr;
            }
#ifndef NDEBUG
            inner_ptr = null;
#endif /* NDEBUG */
         }
      }
ptr(X* x)
      {
         inner_ptr = x;
         if (inner_ptr != null)
         {
            inner_ptr->_ref_count++;
         }
      }
      ///
      /// NOTE: not needed as operator = (const ptr&) serves this purpose
      ///
      /// COOL: cool how methods within a class can appear in any order
      ///
      // ptr& operator = (X* x)
      // {
      //    ASSERT(this != null);
      //    if (inner_ptr != null)
      //    {
      //       assert(inner_ptr->_ref_count > 0); // protect against double deletions
      //       inner_ptr->_ref_count--;
      //       if (inner_ptr->_ref_count == 0)
      //       {
      //          inner_ptr->_ref_count = 1; // protect against internal deletions
      //          delete inner_ptr;
      //       }
      //    }
      //    inner_ptr = x;
      //    if (inner_ptr != null)
      //    {
      //       inner_ptr->_ref_count++;
      //    }
      //    return *this;
      // }
      ///
      /// NOTE: Be careful not to store this pointer in a long-term
      /// variable or else it will wreck the auto-GC system...
      /// (Therefore the Lisp AutoGC system should search for such pointers)
      ///
      /// NOTE: fails if pointer is null, if null is OK, use method get_ptr()
      ///
      X* operator -> () const
      {
         ASSERT(this      != null);
         ASSERT(inner_ptr != null);
         return inner_ptr;
      }
X& operator * () const
      {
         ASSERT(this      != null);
         ASSERT(inner_ptr != null);
         return *inner_ptr;
      }
X* get_ptr() const
      {
         ASSERT(this != null);
         return inner_ptr;
      }
      ///
      /// NOTE: these methods are like Lisp's eq function (not Lisp's equal function)
      ///
      /// NOTE: g++ does not optimise these functions very well...
      ///
      friend bool operator == (const ptr& p1, const ptr& p2)
      {
         if ((&p1 == null) && (&p2 == null))
         {
            return true;
         }
         else if ((&p1 == null) || (&p2 == null))
         {
            return false;
         }
         else
         {
            return (p1.inner_ptr == p2.inner_ptr);
         }
      }
      friend bool operator != (const ptr& p1, const ptr& p2)
      {
         return !(p1 == p2);
      }
#ifdef DAVINS_IO_ONLINE
friend dmp::string_buffer operator + (const dmp::string& str, const ptr& p)
      {
         dmp::string_buffer sb;
         sb << str;
         sb << p.inner_ptr;
         return sb;
      }
      friend dmp::string_buffer operator + (const dmp::string_buffer& csb, const ptr& p)
      {
         dmp::string_buffer sb = const_cast<dmp::string_buffer&>(csb);
         sb << p.inner_ptr;
         return sb;
      }
      ///
      /// NOTE: operator << (Writer&, const ptr&) calls operator << (Writer&,const X&)
      ///
      friend dmp::Writer& operator << (dmp::Writer& w, const ptr<X>& p)
      {
         //CHECKPOINT;
         ASSERT(&w != null);
         ASSERT(&p != null);
         if (p.inner_ptr == null)
         {
            w << "null";
         }
         else
         {
            //CHECKPOINT;
            w << *(p.inner_ptr);
            //CHECKPOINT;
         }
         return w;
      }
      friend dmp::Reader& operator >> (dmp::Reader& r, ptr<X>& p)
      {
         //CHECKPOINT;
         ASSERT(&r != null);
         ASSERT(&p != null);
         //ASSERT(p.inner_ptr == null);
         if (r.looking_at("null"))
         {
            p = null;
            r.next_token(); // more efficient than r.skip("null");
         }
         else
         {
            //CHECKPOINT;
            r >> *(p.inner_ptr);
            //CHECKPOINT;
         }
         //CHECKPOINT;
         return r;
      }
#endif /* DAVINS_IO_ONLINE */
   };
}
#endif /* ALREADY_INCLUDED_2006_LIBD_PTR_HH */
| Back |