#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 |