//////////////////////////////////////////////////////////////////////////////// // Author: Daniel Milton // Copyright: (c) Daniel Milton 2002-2009 //////////////////////////////////////////////////////////////////////////////// namespace stlplus { //////////////////////////////////////////////////////////////////////////////// // simple_ptr_base class //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // constructors, assignments and destructors // create a null pointer template simple_ptr_base::simple_ptr_base(void) : m_pointer(0), m_count(new unsigned(1)) { } // create a pointer containing a *copy* of the object pointer template simple_ptr_base::simple_ptr_base(const T& data) throw(illegal_copy) : m_pointer(C()(data)), m_count(new unsigned(1)) { } // create a pointer containing a dynamically created object // Note: the object must be allocated *by the user* with new // constructor form - must be called in the form simple_ptr x(new type(args)) template simple_ptr_base::simple_ptr_base(T* data) : m_pointer(data), m_count(new unsigned(1)) { } // copy constructor implements counted referencing - no copy is made template simple_ptr_base::simple_ptr_base(const simple_ptr_base& r) : m_pointer(r.m_pointer), m_count(r.m_count) { increment(); } // assignment operator - required, else the output of GCC suffers segmentation faults template simple_ptr_base& simple_ptr_base::operator=(const simple_ptr_base& r) { alias(r); return *this; } // destructor decrements the reference count and delete only when the last reference is destroyed template simple_ptr_base::~simple_ptr_base(void) { if(decrement()) { delete m_pointer; delete m_count; } } ////////////////////////////////////////////////////////////////////////////// // logical tests to see if there is anything contained in the pointer since it can be null template bool simple_ptr_base::null(void) const { return m_pointer==0; } template bool simple_ptr_base::present(void) const { return m_pointer!=0; } template bool simple_ptr_base::operator!(void) const { return m_pointer==0; } template simple_ptr_base::operator bool(void) const { return m_pointer!=0; } ////////////////////////////////////////////////////////////////////////////// // dereference operators and functions template T& simple_ptr_base::operator*(void) throw(null_dereference) { if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator*"); return *m_pointer; } template const T& simple_ptr_base::operator*(void) const throw(null_dereference) { if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator*"); return *m_pointer; } template T* simple_ptr_base::operator->(void) throw(null_dereference) { if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator->"); return m_pointer; } template const T* simple_ptr_base::operator->(void) const throw(null_dereference) { if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator->"); return m_pointer; } ////////////////////////////////////////////////////////////////////////////// // explicit function forms of the above assignment dereference operators template void simple_ptr_base::set_value(const T& data) throw(illegal_copy) { set(C()(data)); } template T& simple_ptr_base::value(void) throw(null_dereference) { if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::value"); return *m_pointer; } template const T& simple_ptr_base::value(void) const throw(null_dereference) { if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::value"); return *m_pointer; } template void simple_ptr_base::set(T* data) { unsigned& count = *m_count; if (count<=1) delete m_pointer; else { --count; m_count = new unsigned(1); } m_pointer = data; } template T* simple_ptr_base::pointer(void) { return m_pointer; } template const T* simple_ptr_base::pointer(void) const { return m_pointer; } //////////////////////////////////////////////////////////////////////////////// // functions to manage counted referencing template void simple_ptr_base::increment(void) { ++(*m_count); } template bool simple_ptr_base::decrement(void) { unsigned& count = *m_count; --count; return count == 0; } // make this an alias of the passed object template void simple_ptr_base::alias(const simple_ptr_base& r) { // make it alias-copy safe - this means that I don't try to do the // assignment if r is either the same object or an alias of it if (m_pointer==r.m_pointer) return; if(decrement()) { delete m_pointer; delete m_count; } m_pointer = r.m_pointer; m_count = r.m_count; increment(); } template bool simple_ptr_base::aliases(const simple_ptr_base& r) const { return m_count == r.m_count; } template unsigned simple_ptr_base::alias_count(void) const { return *m_count; } template void simple_ptr_base::clear(void) { set(0); } template void simple_ptr_base::clear_unique(void) { set(0); // no difference between clear and clear_unique with the simple_ptr } template void simple_ptr_base::make_unique(void) throw(illegal_copy) { unsigned& count = *m_count; if (count <= 1) return; --count; if (m_pointer) m_pointer = C()(*m_pointer); m_count = new unsigned(1); } template void simple_ptr_base::copy(const simple_ptr_base& data) throw(illegal_copy) { alias(data); make_unique(); } #ifdef STLPLUS_MEMBER_TEMPLATES // dynamic cast of underlying pointer to a derived/parent template template simple_ptr_base simple_ptr_base::dyn_cast(void) const { simple_ptr_base rtn; rtn.m_pointer = dynamic_cast(m_pointer); if (rtn.m_pointer) { delete rtn.m_count; rtn.m_count = m_count; rtn.increment(); } return rtn; } // static cast of underlying pointer to a derived/parent template template simple_ptr_base simple_ptr_base::stat_cast(void) const { simple_ptr_base rtn; rtn.m_pointer = static_cast(m_pointer); if (rtn.m_pointer) { delete rtn.m_count; rtn.m_count = m_count; rtn.increment(); } return rtn; } // cast of underlying pointer to a base - while keeping the same ref-counted object template template simple_ptr_base simple_ptr_base::cast(void) const { simple_ptr_base rtn; rtn.m_pointer = (T2*)m_pointer; if (rtn.m_pointer) { delete rtn.m_count; rtn.m_count = m_count; rtn.increment(); } return rtn; } #endif // internal function for distinguishing unique simple_ptr objects // used for example in persistence routines template unsigned* simple_ptr_base::_count(void) const { return m_count; } template T* simple_ptr_base::_pointer(void) const { return m_pointer; } template void simple_ptr_base::_make_alias(T* pointer, unsigned* count) { // make it alias-copy safe - this means that I don't try to do the // assignment if r is either the same object or an alias of it if (m_count != count) { if(decrement()) { delete m_pointer; delete m_count; } m_pointer = pointer; m_count = count; increment(); } } //////////////////////////////////////////////////////////////////////////////// } // end namespace stlplus