    // Copyright (C) 2006  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #undef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_
    #ifdef DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_

    #include "../algs.h"
    #include "../memory_manager/memory_manager_kernel_abstract.h"

    namespace dlib
    {
        template <
            typename T,
            typename factory
            >
        class memory_manager_global
        {
            /*!
                REQUIREMENTS ON T
                    T must have a default constructor.

                REQUIREMENTS ON factory
                    factory must be defined as follows:
                    struct factory
                    {
                        template <typename U>
                        struct return_type {
                            typedef typename memory_manager_type<U> type;
                        };

                        template <typename U>
                        static typename return_type<U>::type* get_instance (
                        );
                        / *!
                            ensures
                                - returns a pointer to an instance of a memory_manager object
                                  where memory_manager_type implements the interface defined
                                  by dlib/memory_manager/memory_manager_kernel_abstract.h
                        !* /
                    };

                WHAT THIS OBJECT REPRESENTS
                    This object represents some kind of global memory manager or memory pool.
                    It is identical to the memory_manager object except that it gets all of
                    its allocations from a global instance of a memory_manager object which
                    is provided by the factory object's static member get_instance().

                THREAD SAFETY
                    This object is, by itself, threadsafe.  However, if you want to use this
                    object in multiple threads then you must ensure that your factory is
                    threadsafe.  This means its factory::get_instance() method should be
                    threadsafe and the memory_manager object it returns must also be threadsafe.
            !*/

            public:

                typedef typename factory::template return_type<T>::type mm_global_type;

                typedef T type;

                template <typename U>
                struct rebind {
                    typedef memory_manager_global<U,factory> other;
                };

                memory_manager_global(
                );
                /*!
                    ensures
                        - #*this is properly initialized
                        - #get_global_memory_manager() == the memory manager that was
                          returned by a call to factory::get_instance<T>()
                    throws
                        - std::bad_alloc
                !*/

                virtual ~memory_manager_global(
                );
                /*!
                    ensures
                        - This destructor has no effect on the global memory_manager
                          get_global_memory_manager().
                !*/

                size_t get_number_of_allocations (
                ) const;
                /*!
                    ensures
                        - returns get_global_memory_manager().get_number_of_allocations()
                !*/

                mm_global_type& get_global_memory_manager (
                );
                /*!
                    ensures
                        - returns a reference to the global memory manager instance being
                          used by *this.
                !*/

                T* allocate (
                );
                /*!
                    ensures
                        - #get_number_of_allocations() == get_number_of_allocations() + 1
                        - returns get_global_memory_manager().allocate()
                    throws
                        - std::bad_alloc or any exception thrown by T's constructor.
                            If this exception is thrown then the call to allocate()
                            has no effect on #*this.
                !*/

                void deallocate (
                    T* item
                );
                /*!
                    requires
                        - item == is a pointer to memory that was obtained from a call to
                          the get_global_memory_manager() object's allocate() method.
                        - the memory pointed to by item hasn't already been deallocated.
                    ensures
                        - calls get_global_memory_manager().deallocate(item)
                        - #get_number_of_allocations() == get_number_of_allocations() - 1
                !*/

                T* allocate_array (
                    size_t size
                );
                /*!
                    ensures
                        - #get_number_of_allocations() == get_number_of_allocations() + 1
                        - returns get_global_memory_manager().allocate_array()
                    throws
                        - std::bad_alloc or any exception thrown by T's constructor.
                            If this exception is thrown then the call to allocate_array()
                            has no effect on #*this.
                !*/

                void deallocate_array (
                    T* item
                );
                /*!
                    requires
                        - item == is a pointer to memory that was obtained from a call to
                          the get_global_memory_manager() object's allocate_array() method.
                        - the memory pointed to by item hasn't already been deallocated.
                    ensures
                        - calls get_global_memory_manager().deallocate_array(item)
                        - #get_number_of_allocations() == get_number_of_allocations() - 1
                !*/

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

            private:

                // restricted functions
                memory_manager_global(memory_manager_global&);        // copy constructor
                memory_manager_global& operator=(memory_manager_global&);    // assignment operator
        };

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

    }

    #endif // DLIB_MEMORY_MANAGER_GLOBAl_ABSTRACT_