    // Copyright (C) 2007  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_WEAK_PTr_
    #define DLIB_WEAK_PTr_

    #include <algorithm>
    #include <memory>
    #include "shared_ptr.h"
    #include "../algs.h"
    #include "weak_ptr_abstract.h"

    namespace dlib {

        template <
            typename T
            >
        class weak_ptr
        {

            /*!
                CONVENTION
                    - if (weak_node != 0) then
                        - data == valid pointer to shared data
                        - weak_node->ref_count == the number of weak_ptrs that reference this->data
                    - else
                        - data == 0

                    - expired() == ((weak_node == 0) || (weak_node->shared_node == 0))
                    - if (expired() == false) then
                        - use_count() == weak_node->shared_node->ref_count
                    - else
                        - use_count() == 0
            !*/

        public:
            typedef T element_type;

            weak_ptr(
            ) : data(0), weak_node(0)
            {
            }

            template<typename Y>
            weak_ptr(
                const shared_ptr<Y>& r
            )
            {
                data = r.data;
                if (r.shared_node)
                {
                    if (r.shared_node->weak_node)
                    {
                        weak_node = r.shared_node->weak_node;
                        weak_node->ref_count += 1;
                    }
                    else
                    {
                        weak_node = new weak_ptr_node(r.shared_node);
                        r.shared_node->weak_node = weak_node;
                    }
                }
                else
                {
                    weak_node = 0;
                }
            }

            weak_ptr(
                const weak_ptr& r
            )
            {
                data = r.data;
                weak_node = r.weak_node;
                if (weak_node)
                    weak_node->ref_count += 1;
            }

            template<typename Y>
            weak_ptr(
                const weak_ptr<Y>& r
            )
            {
                data = r.data;
                weak_node = r.weak_node;
                if (weak_node)
                    weak_node->ref_count += 1;
            }

            ~weak_ptr(
            )
            {
                if (weak_node)
                {
                    // make note that this weak_ptr is being destroyed
                    weak_node->ref_count -= 1;

                    // if this is the last weak_ptr then we should clean up our stuff
                    if (weak_node->ref_count == 0)
                    {
                        if (expired() == false)
                            weak_node->shared_node->weak_node = 0;
                        delete weak_node;
                    }
                }
            }

            weak_ptr& operator= (
                const weak_ptr& r
            )
            {
                weak_ptr(r).swap(*this);
                return *this;
            }

            template<typename Y>
            weak_ptr& operator= (
                const weak_ptr<Y>& r
            )
            {
                weak_ptr(r).swap(*this);
                return *this;
            }

            template<typename Y>
            weak_ptr& operator=(
                const shared_ptr<Y>& r
            )
            {
                weak_ptr(r).swap(*this);
                return *this;
            }

            long use_count(
            ) const
            {
                if (expired())
                    return 0;
                else
                    return weak_node->shared_node->ref_count;
            }

            bool expired() const { return weak_node == 0 || weak_node->shared_node == 0; }

            shared_ptr<T> lock(
            ) const
            {
                if (expired())
                    return shared_ptr<T>();
                else
                    return shared_ptr<T>(*this);
            }

            void reset(
            )
            {
                weak_ptr().swap(*this);
            }

            void swap(
                weak_ptr<T>& b
            )
            {
                std::swap(data, b.data);
                std::swap(weak_node, b.weak_node);
            }

            template <typename Y>
            bool _private_less (
                const weak_ptr<Y>& rhs
            ) const
            {
                if (expired())
                {
                    if (rhs.expired())
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                else
                {
                    if (rhs.expired())
                    {
                        return false;
                    }
                    else
                    {
                        // in this case they have both not expired so lets
                        // compare the shared_node pointers
                        return (weak_node->shared_node) < (rhs.weak_node->shared_node);
                    }
                }
            }

        private:

            template <typename Y> friend class shared_ptr;
            template <typename Y> friend class weak_ptr;

            T* data;
            weak_ptr_node* weak_node;
        };

        template<typename T, typename U>
        bool operator< (
            const weak_ptr<T>& a,
            const weak_ptr<U>& b
        )
        {
            return a._private_less(b);
        }

        template<typename T>
        void swap(
            weak_ptr<T>& a,
            weak_ptr<T> & b
        ) { a.swap(b); }
    }

    #endif // DLIB_WEAK_PTr_