#pragma once #include "ref_counted.h" #include #include #include #include #include "lib_begin.h" namespace cgv { /// namespace for data management components namespace data { // extern CGV_API bool validate_delete(const void* ptr); template class ref_ptr; /// struct used to make ref pointers to ref_counted friends of ref_counted class ref_ptr_tag { protected: /// increment the count of a ref counted object void inc_ref_count(const ref_counted* ptr) const { ptr->set_ref_count(ptr->get_ref_count()+1); } /// decrement the count of a ref counted object and return whether to delete the object bool dec_ref_count(const ref_counted* ptr) const { int count = ptr->get_ref_count(); if (count > 0) { ptr->set_ref_count(count-1); return count == 1; } // ERROR: zero ref count decremented assert(0); return false; } }; template class ref_ptr_impl { protected: friend class ref_ptr_impl; /// struct to store the pointer with a count struct counter_type { counter_type(T* p, int c) : ptr(p), count(c) {} T* ptr; int count; }; /// store pointer to counter struct mutable counter_type* counter; /// decrement the count, delete if it is 0 void release() { if (counter) { if (--counter->count == 0) { delete counter->ptr; counter->ptr = 0; delete counter; } counter = 0; } } /// return the pointer itself T* ref () const { return counter ? counter->ptr : 0; } /// construct reference counted pointer explicit ref_ptr_impl(T* p = 0) : counter(0) { if (p) counter = new counter_type(p, 1); } /// copy construct from same pointer type and increment count ref_ptr_impl(const ref_ptr_impl& r) : counter(r.counter) { if (counter) ++counter->count; } /// copy construct from pointer of derived type with virtual destructor template ref_ptr_impl(const ref_ptr_impl& s) { // ref_ptr conversion only valid if T is base of S CGV_DEFINES_ASSERT(type::cond::is_base_of::value); // and T has a virtual destructor CGV_DEFINES_ASSERT(type::cond::has_virtual_destructor::value); // after validity checks, set pointer counter = reinterpret_cast(s.counter); // and increment reference count if (counter) ++counter->count; } public: /// return current count int get_count() const { return counter ? counter->count : 0; } }; template class ref_ptr_impl : public ref_ptr_tag { T* ptr; protected: /// if the pointer had been initialized before, decrement reference count and release pointer, if necessary delete instance void release() { if (ptr) { if (dec_ref_count(ptr)) { // if (validate_delete(ptr)) delete ptr; } ptr = 0; } } /// return the pointer itself T* ref () const { return ptr; } /// construct from pointer and increment reference count explicit ref_ptr_impl(T* p) : ptr(p) { if (ptr) inc_ref_count(ptr); } /// copy construct from same pointer type and increment count ref_ptr_impl(const ref_ptr_impl& r) : ptr(r.ref()) { if (ptr) inc_ref_count(ptr); } /// copy construct from pointer of derived type with virtual destructor template ref_ptr_impl(const ref_ptr_impl& s) { // ref_ptr conversion only valid if T is base of S CGV_DEFINES_ASSERT(type::cond::is_base_of::value); // and T has a virtual destructor CGV_DEFINES_ASSERT(type::cond::has_virtual_destructor::value); // after validity checks, set pointer with a very bad hack!! ptr = static_cast&>(s).operator->(); // and increment reference count if (ptr) inc_ref_count(ptr); } public: // void kill() { ptr = 0; } /// return the reference count int get_count() const { return ptr ? ptr->get_ref_count() : 0; } }; /** reference counted pointer, which can work together with types that are derived from ref_counted, in which case the reference count of ref_counted is used. Otherwise a reference count is allocated and access to the stored instance needs to follow two pointers. */ template ::value> class ref_ptr : public ref_ptr_impl { public: /// type of the reference counted pointer typedef ref_ptr this_type; /// type of base class that implements the reference count specific methods typedef ref_ptr_impl base_type; public: /// construction from pointer or empty if pointer is not given ref_ptr(T* p = 0) : base_type(p) {} /// copy constructor for reference pointers of the same type ref_ptr(const this_type& r) : base_type(r) {} /// destruct reference counted pointer ~ref_ptr() { this->release(); } /// allow to copy ref_ptr to a ref_ptr if T is a base class of S and if T has a virtual destructor template ref_ptr(const ref_ptr& s) : base_type(s) {} /// use static cast to convert from T to S if T is a base class of S and has a virtual destructor template ref_ptr up_cast() const { // ref_ptr conversion only valid if T is base of S CGV_DEFINES_ASSERT(type::cond::is_base_of::value); // and S has a virtual destructor CGV_DEFINES_ASSERT(type::cond::has_virtual_destructor::value); // after validity checks, return converted pointer return ref_ptr( *reinterpret_cast*>(this) ); } /// assignment to pointer of same type this_type& operator = (const this_type& r) { if (this == &r) return *this; this->release(); new (this) this_type(r); return *this; } /// assignment to pointer of derived type with virtual destructor template this_type& operator = (const ref_ptr& r) { if (this == (const this_type*)&r) return *this; return *this = this_type(r); } /// access to element T& operator*() const { return *this->ref(); } /// access to element pointer T* operator->() const { return this->ref(); } /// compare by pointer bool operator == (const this_type& r) const { return this->ref() == r.ref(); } /// compare by pointer bool operator < (const this_type& r) const { return this->ref() < r.ref(); } /// compare by pointer bool operator != (const this_type& r) const { return this->ref() != r.ref(); } /// check if this is the only reference bool unique() const { return this->get_count() <= 1; } /// check if pointer is not yet set bool empty() const { return this->get_count() == 0; } /// conversion to bool results in false if the stored pointer is a null pointer operator bool () const { return !empty(); } /// set to null pointer void clear() { this->release(); } }; } } #include