// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_REFERENCE_COUNTER_KERNEl_1_ #define DLIB_REFERENCE_COUNTER_KERNEl_1_ #include "reference_counter_kernel_abstract.h" #include "../algs.h" namespace dlib { template < typename T, typename copy = copy_functor<T> > class reference_counter_kernel_1 { /*! INITIAL VALUE *data = item of type T with its initial value *count = 1 CONVENTION *data = pointer to item of type T *count = number of references to *data if clear() threw an exception then count = 0 and data is not a valid pointer !*/ public: typedef T type; reference_counter_kernel_1 ( ); inline reference_counter_kernel_1 ( const reference_counter_kernel_1& item ); virtual ~reference_counter_kernel_1 ( ); void clear ( ); T& modify ( ); inline const T& access ( ) const; inline reference_counter_kernel_1& operator= ( const reference_counter_kernel_1& rhs ); inline void swap ( reference_counter_kernel_1& item ); private: T* data; unsigned long* count; mutable copy copy_item; }; template < typename T, typename copy > inline void swap ( reference_counter_kernel_1<T,copy>& a, reference_counter_kernel_1<T,copy>& b ) { a.swap(b); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename T, typename copy > reference_counter_kernel_1<T,copy>:: reference_counter_kernel_1 ( ) { data = new T; try { count = new unsigned long; } catch (...) { delete data; throw; } *count = 1; } // ---------------------------------------------------------------------------------------- template < typename T, typename copy > reference_counter_kernel_1<T,copy>:: reference_counter_kernel_1 ( const reference_counter_kernel_1<T,copy>& item ) : data(item.data), count(item.count) { ++(*count); } // ---------------------------------------------------------------------------------------- template < typename T, typename copy > reference_counter_kernel_1<T,copy>:: ~reference_counter_kernel_1 ( ) { if (*count > 1) { // if there are other references to this data --(*count); } else { // if there are no other references to this data delete count; delete data; } } // ---------------------------------------------------------------------------------------- template < typename T, typename copy > void reference_counter_kernel_1<T,copy>:: clear ( ) { // if an exception was thrown last time clear() was called then do this if (count == 0) { data = new T; try { count = new unsigned long; } catch (...) { delete data; throw; } *count = 1; } // if there are other references to the data then do this else if (*count > 1) { --(*count); try { data = new T; } catch (...) { count = 0; throw; } try { count = new unsigned long; } catch (...) { delete data; count = 0; throw; } *count = 1; } else { // if there are no other references to this data *count = 1; delete data; try { data = new T; } catch (...) { delete count; count = 0; throw; } } } // ---------------------------------------------------------------------------------------- template < typename T, typename copy > T& reference_counter_kernel_1<T,copy>:: modify ( ) { // if this is not the only reference then make a new copy if ( *count > 1 ) { T& old_data = *data; unsigned long& old_count = *count; // get memory for the new copy try { data = new T; } catch (...) { data = &old_data; throw; } try { count = new unsigned long; } catch (...) {delete data; data = &old_data; count = &old_count; throw;} // decrement the number of references to old_data --(old_count); *count = 1; // make a copy of the old data try { copy_item(old_data,*data); } catch (...) { delete data; delete count; data = &old_data; count = &old_count; } } return *data; } // ---------------------------------------------------------------------------------------- template < typename T, typename copy > const T& reference_counter_kernel_1<T,copy>:: access ( ) const { return *data; } // ---------------------------------------------------------------------------------------- template < typename T, typename copy > reference_counter_kernel_1<T,copy>& reference_counter_kernel_1<T,copy>:: operator= ( const reference_counter_kernel_1<T,copy>& rhs ) { if (this == &rhs) return *this; // delete the current data if this is the last reference to it if (*count > 1) { // if there are other references to this data --(*count); } else { // if there are no other references to this data delete count; delete data; } // copy the pointers count = (rhs.count); data = (rhs.data); ++(*count); return *this; } // ---------------------------------------------------------------------------------------- template < typename T, typename copy > void reference_counter_kernel_1<T,copy>:: swap ( reference_counter_kernel_1<T,copy>& item ) { T* data_temp = data; unsigned long* count_temp = count; data = item.data; count = item.count; item.data = data_temp; item.count = count_temp; } // ---------------------------------------------------------------------------------------- } #endif // DLIB_REFERENCE_COUNTER_KERNEl_1_