#if !defined(__ptr_inl_include__) #error "ptr.inl may only be included from ptr.h" #endif // !defined(__ptr_inl_include__) #ifndef __ptr_inl__ #define __ptr_inl__ #include struct ptr_counter { ptr_counter() : _count(0) { /* empty */ }; void inc() { _count++; } void dec() { _count--; } unsigned _count; }; // // default construction // template inline ptr::ptr() : _ptr(0), _counter(0) { // empty } // // copying // template inline ptr::ptr(const ptr& other) : _ptr(0), _counter(0) { // defer to copy assignment operator *this = other; } template inline ptr& ptr::operator=(const ptr& other) { // make certain it's not trying to copy assign itself to itself if ( this != &other ) { // take the pointer and counter from the other and increment the count // TODO should we check that the other counter is non-zero? grab(other._ptr, other._counter); } // send back a reference to this object return *this; } // // copying from a normal pointer // template inline ptr::ptr(X* normal_ptr) : _ptr(0), _counter(0) { // defer to operator *this = normal_ptr; } template inline ptr& ptr::operator=(X* normal_ptr) { // initialize pointer and create new reference counter grab(normal_ptr, 0); // send back a reference to this object return *this; } // // destructor // template inline ptr::~ptr() { // decrement count and possibly release pointer drop(); } // // take a pointer as ours and increment reference count // template inline void ptr::grab(X* normal_ptr, ptr_counter* counter) { // drop any pointer+counter we may already have drop(); // if the pointer is 0, we're finished if ( !normal_ptr ) { // zeroed out, nothing to do return; } // copy pointer _ptr = normal_ptr; // copy or create a new counter _counter = counter ? counter : new ptr_counter; assert(_counter); // increment reference count _counter->inc(); } // // reset our pointer and counter to zero and decrement reference count // and, possibly, delete the pointer (if reference count goes to zero) // template inline void ptr::drop() { // check to see if we have anything to drop if ( valid() ) { // decrement the count _counter->dec(); // check if this is the last reference if ( unreferenced() ) { // this is the last reference, delete the pointer and counter delete _ptr; delete _counter; } // now reset ("drop") the pointer and the counter _ptr = 0; _counter = 0; } } // // comparison // template inline bool ptr::operator==(const ptr& other) const { return _ptr == other._ptr; } template inline bool ptr::operator!=(const ptr& other) const { return _ptr != other._ptr; } template inline bool ptr::operator<(const ptr& other) const { return _ptr < other._ptr; } template inline bool ptr::operator<=(const ptr& other) const { return _ptr <= other._ptr; } template inline bool ptr::operator>(const ptr& other) const { return _ptr > other._ptr; } template inline bool ptr::operator>=(const ptr& other) const { return _ptr >= other._ptr; } // // use the pointer // template inline X* ptr::operator->() const { assert(_ptr); return _ptr; } template inline X& ptr::operator*() const { assert(_ptr); return *_ptr; } template inline X& ptr::operator[](size_t i) { assert(_ptr); return _ptr[i]; } template inline const X& ptr::operator[](size_t i) const { assert(_ptr); return _ptr[i]; } // // check whether pointer is valid // template inline ptr::operator bool() const { return valid(); } template inline bool ptr::valid() const { return _ptr && _counter; } // // miscellaneous utility methods // template inline unsigned ptr::copies() const { return valid() ? _counter->_count : 0; } template inline bool ptr::shared() const { return copies() > 1; } template inline bool ptr::unique() const { return copies() == 1; } template inline bool ptr::unreferenced() const { return copies() == 0; } // // default construction // template inline array_ptr::array_ptr() : _ptr(0), _counter(0) { // empty } // // copying // template inline array_ptr::array_ptr(const array_ptr& other) : _ptr(0), _counter(0) { // defer to copy assignment operator *this = other; } template inline array_ptr& array_ptr::operator=(const array_ptr& other) { // make certain it's not trying to copy assign itself to itself if ( this != &other ) { // take the pointer and counter from the other and increment the count // TODO should we check that the other counter is non-zero? grab(other._ptr, other._counter); } // send back a reference to this object return *this; } // // copying from a normal pointer // template inline array_ptr::array_ptr(X* normal_ptr) : _ptr(0), _counter(0) { // defer to operator *this = normal_ptr; } template inline array_ptr& array_ptr::operator=(X* normal_ptr) { // initialize pointer and create new reference counter grab(normal_ptr, 0); // send back a reference to this object return *this; } // // destructor // template inline array_ptr::~array_ptr() { // decrement count and possibly release pointer drop(); } // // take a pointer as ours and increment reference count // template inline void array_ptr::grab(X* normal_ptr, ptr_counter* counter) { // drop any pointer+counter we may already have drop(); // if the pointer is 0, we're finished if ( !normal_ptr ) { // zeroed out, nothing to do return; } // copy pointer _ptr = normal_ptr; // copy or create a new counter _counter = counter ? counter : new ptr_counter; assert(_counter); // increment reference count _counter->inc(); } // // reset our pointer and counter to zero and decrement reference count // and, possibly, delete the pointer (if reference count goes to zero) // template inline void array_ptr::drop() { // check to see if we have anything to drop if ( valid() ) { // decrement the count _counter->dec(); // check if this is the last reference if ( unreferenced() ) { // this is the last reference, delete the pointer and counter delete[] _ptr; delete _counter; } // now reset ("drop") the pointer and the counter _ptr = 0; _counter = 0; } } // // comparison // template inline bool array_ptr::operator==(const array_ptr& other) const { return _ptr == other._ptr; } template inline bool array_ptr::operator!=(const array_ptr& other) const { return _ptr != other._ptr; } template inline bool array_ptr::operator<(const array_ptr& other) const { return _ptr < other._ptr; } template inline bool array_ptr::operator<=(const array_ptr& other) const { return _ptr <= other._ptr; } template inline bool array_ptr::operator>(const array_ptr& other) const { return _ptr > other._ptr; } template inline bool array_ptr::operator>=(const array_ptr& other) const { return _ptr >= other._ptr; } // // use the pointer // template inline X* array_ptr::operator->() const { assert(_ptr); return _ptr; } template inline X& array_ptr::operator*() const { assert(_ptr); return *_ptr; } template inline X& array_ptr::operator[](size_t i) { assert(_ptr); return _ptr[i]; } template inline const X& array_ptr::operator[](size_t i) const { assert(_ptr); return _ptr[i]; } // // check whether pointer is valid // template inline array_ptr::operator bool() const { return valid(); } template inline bool array_ptr::valid() const { return _ptr && _counter; } // // miscellaneous utility methods // template inline unsigned array_ptr::copies() const { return valid() ? _counter->_count : 0; } template inline bool array_ptr::shared() const { return copies() > 1; } template inline bool array_ptr::unique() const { return copies() == 1; } template inline bool array_ptr::unreferenced() const { return copies() == 0; } #endif // __ptr_inl__