// Copyright (C) 2003  Davis E. King (davisking@users.sourceforge.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_
#ifdef DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_

#include "../algs.h"

namespace dlib
{

    template <
        typename T,
        typename copy = copy_functor<T>
        >
    class reference_counter
    {

        /*!
            REQUIREMENTS ON T
                T must have a default constructor

            REQUIREMENTS ON copy
                it should be a function object that copies an object of type T. and
                it must have a default constructor and
                operator() should be overloaded as 
                void operator()(const T& source, T& destination);
                copy may throw any exception 

            POINTERS AND REFERENCES TO INTERNAL DATA
                swap() and access() functions do not invalidate pointers or 
                references to internal data.
                All other functions have no such guarantee
  

            INITIAL VALUE
                reference_counter contains one object of type T and
                this object of type T has its initial value

            WHAT THIS OBJECT REPRESENTS
                This object represents a container for an object of type T and 
                provides reference counting capabilities for the object it contains   

                Also note that unless specified otherwise, no member functions
                of this object throw exceptions.

        !*/

        public:

            typedef T type;

            reference_counter (
            );
            /*!
                ensures 
                    - #*this is properly initialized
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
            !*/

            reference_counter ( 
                const reference_counter& item
            );
            /*!
                ensures
                    - #access() == item.access()
            !*/

            virtual ~reference_counter (
            ); 
            /*!
                ensures
                    - all memory associated with *this has been released
            !*/

            void clear (
            );
            /*!
                ensures
                    - #*this has its initial value
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        if this exception is thrown then *this is unusable 
                        until clear() is called and succeeds
            !*/

            T& modify (
            );
            /*!
                ensures
                    - returns a non-const reference to the item contained in *this 
                    - the item is ok to modify.  i.e. there are no other references to it
                throws
                    - std::bad_alloc or any exception thrown by T's constructor
                        modify() may throw this exception if there are other references
                        to the item and there is not enough memory to copy it. If modify()
                        throws then it has no effect.    
            !*/

            const T& access (
            ) const;
            /*!
                ensures
                    - returns a const reference to the item contained in *this 
                    - there may be other references to to the item
            !*/

            reference_counter& operator= (
                const reference_counter& rhs
            );
            /*!
                ensures
                    - #access() == rhs.access() 
            !*/

            void swap (
                reference_counter& item
            );
            /*!
                ensures
                    - swaps *this and item
            !*/ 

    };

    template <
        typename T,
        typename copy
        >
    inline void swap (
        reference_counter<T,copy>& a, 
        reference_counter<T,copy>& b 
    ) { a.swap(b); }  
    /*!
        provides a global swap function
    !*/

}

#endif // DLIB_REFERENCE_COUNTER_KERNEl_ABSTRACT_

