    // 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_