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

    #include "../algs.h"
    #include "memory_manager_stateless_kernel_abstract.h"
    #include "../threads.h"

    namespace dlib
    {
        template <
            typename T,
            typename mem_manager
            >
        class memory_manager_stateless_kernel_2
        {
            /*!
                REQUIREMENTS ON mem_manager
                    mem_manager must be an implementation of memory_manager/memory_manager_kernel_abstract.h

                CONVENTION
                    this object has a single global instance of mem_manager
            !*/

            public:

                typedef T type;
                const static bool is_stateless = true;

                template <typename U>
                struct rebind {
                    typedef memory_manager_stateless_kernel_2<U,mem_manager> other;
                };

                memory_manager_stateless_kernel_2(
                )
                {
                    // call this just to make sure the mutex is is initialized before
                    // multiple threads start calling the member functions.
                    global_mutex();
                }

                virtual ~memory_manager_stateless_kernel_2(
                ) {}

                T* allocate (
                )
                {
                    auto_mutex M(global_mutex());
                    return global_mm().allocate();
                }

                void deallocate (
                    T* item
                )
                {
                    auto_mutex M(global_mutex());
                    return global_mm().deallocate(item);
                }

                T* allocate_array (
                    size_t size
                )
                {
                    auto_mutex M(global_mutex());
                    return global_mm().allocate_array(size);
                }

                void deallocate_array (
                    T* item
                )
                {
                    auto_mutex M(global_mutex());
                    return global_mm().deallocate_array(item);
                }

                void swap (memory_manager_stateless_kernel_2&)
                {}

            private:

                static mutex& global_mutex (
                )
                {
                    static mutex lock;
                    return lock;
                }

                typedef typename mem_manager::template rebind<T>::other rebound_mm_type;

                static rebound_mm_type& global_mm (
                )
                {
                    static rebound_mm_type mm;
                    return mm;
                }

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

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

    }

    #endif // DLIB_MEMORY_MANAGER_STATELESs_2_