// bdlcc_objectpool.h                                                 -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BDLCC_OBJECTPOOL
#define INCLUDED_BDLCC_OBJECTPOOL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a thread-safe object pool.
//
//@CLASSES:
//  bdlcc::ObjectPool: thread-safe container of managed objects
//  bdlcc::ObjectPoolFunctors: namespace for resetter/creator implementations
//
//@SEE_ALSO: bdlcc_sharedobjectpool
//
//@DESCRIPTION: This component provides a generic thread-safe pool of objects,
// 'bdlcc::ObjectPool', using the acquire-release idiom and a 'struct' with
// useful functors for a pool of objects, 'bdlcc::ObjectPoolFunctors'.  An
// object pool provides two main methods: 'getObject', which returns an object
// from the pool, and 'releaseObject', which returns an object to the pool for
// further reuse (thus avoiding the overhead of object construction and
// destruction).  A major requirement of using the object pool is that any call
// to 'getObject' can be satisfied by any object in the pool.
//
///Thread Safety
///-------------
// The 'bdlcc::ObjectPool' class template is fully thread-safe (see
// {'bsldoc_glossary'|Fully Thread-Safe}), assuming that the allocator is fully
// thread-safe.  Each method is executed by the calling thread.
//
///Object Construction and Destruction
///-----------------------------------
// The object pool owns the memory required to store the pooled objects, and
// manages the construction, resetting, and destruction of objects.  The user
// may supply functors to create objects and to reset them to a valid state for
// their return to the pool.  Alternatively, this component supplies reasonable
// defaults.  Upon destruction, the object pool deallocates all memory
// associated with the objects in the pool.
//
// The object pool also implements the 'bdlma::Factory' protocol for TYPE.  Its
// 'createObject' and 'deleteObject' methods are provided *only* for this
// purpose and should not be invoked directly (they are just synonyms for
// 'getObject' and 'releaseObject', respectively).  The pool can thus be used
// anywhere a 'bdlma::Factory' (or, therefore, a 'bdlma::Deleter') is expected.
//
///Integrating with 'bslma::ManagedPtr' and 'bsl::shared_ptr'
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// A 'bdlcc::ObjectPool' is designed to work with both managed and shared
// pointer types.  Note however, that 'bdlcc_sharedobjectpool' is an
// object-pool specifically designed for use with shared pointers.
//
// Because 'bdlcc::ObjectPool' provides a 'deleteObject' method, it can serve
// as a factory of both 'bslma::ManagedPtr' and 'bsl::shared_ptr' objects.  For
// example, to create a managed pointer from an object pool of 'bsl::string'
// objects:
//..
//  bdlcc::ObjectPool<bsl::string> pool;
//  bslma::ManagedPtr<bsl::string> managedPtr(pool.getObject(), &pool);
//..
// To create a shared pointer (using the same object pool):
//..
//  bslma::Allocator *allocator = bslma::Default::allocator();
//  bsl::shared_ptr<bsl::string> sharedPtr(pool.getObject(), &pool, allocator);
//..
// Note that an allocator is a *required* argument to the 'bsl::shared_ptr'
// constructor used here, and the provided allocator is used to supply memory
// for the internal representation of the pointer, and not to allocate memory
// for the object itself.
//
///Creator and Resetter Template Contract
///--------------------------------------
// 'bdlcc::ObjectPool' is templated on two types 'CREATOR' and 'RESETTER' in
// addition to the underlying object 'TYPE'.  Objects of these types may be
// provided at construction.  The namespace 'bdlcc::ObjectPoolFunctors'
// provides several commonly used implementations.  The creator will be invoked
// as: 'void(*)(void*, bslma::Allocator*)'.  The resetter will be invoked as:
// 'void(*)(TYPE*)'.  The creator functor is called to construct a new object
// of the parameterized 'TYPE' when the pool must be expanded (and thus it
// typically invokes placement 'new' and passes its allocator argument to the
// constructor of 'TYPE').  The resetter functor is called before each object
// is returned to the pool, and is required to put the object into a state such
// that it is ready to be reused.  The defaults for these types are as follows:
//..
//    CREATOR  = bdlcc::ObjectPoolFunctors::DefaultCreator
//    RESETTER = bdlcc::ObjectPoolFunctors::Nil
//..
// 'bdlcc::ObjectPoolFunctors::Nil' is a no-op; it is only suitable if the
// objects stored in the pool are *always* in a valid state to be reused.
// Otherwise another kind of 'RESETTER' should be provided.  In
// 'bdlcc::ObjectPoolFunctors', the classes 'Clear', 'RemoveAll', and 'Reset'
// are all acceptable types for 'RESETTER'.  Since these functor types are
// fully inlined, it is generally most efficient to define 'reset' (or 'clear'
// or 'removeAll') in the underlying 'TYPE' and allow the functor to call that
// method.  The 'CREATOR' functor defaults to an object that invokes the
// default constructor with placement new, passing the allocator argument if
// the type traits of the object indicate it uses an allocator (see
// 'bslalg_typetraits').  If a custom creator functor or a custom 'CREATOR'
// type is specified, it is the user's responsibility to ensure that it
// correctly passes its allocator argument to the constructor of 'TYPE' if
// 'TYPE' takes an allocator.
//
///Exception safety
///----------------
// There are two potential sources of exceptions in this component: memory
// allocation and object construction.  The object pool is exception-neutral
// with full guarantee of rollback for the following methods: if an exception
// is thrown in 'getObject', 'reserveCapacity', or 'increaseCapacity', then the
// pool is in a valid unmodified state (i.e., identical to its state prior to
// the call to 'getObject').  No other method of 'bdlcc::ObjectPool' can throw.
//
///Pool replenishment policy
///-------------------------
// The 'growBy' parameter can be specified in the pool's constructor to
// instruct the pool how to increase its capacity each time the pool is
// depleted.  If 'growBy' is positive, the pool always replenishes itself with
// enough objects to satisfy at least 'growBy' object requests before the next
// replenishment.  If 'growBy' is negative, the pool will increase its capacity
// geometrically until it exceeds the internal maximum (which is
// implementation-defined), and after that it will be replenished with constant
// number of objects.  If 'growBy' is not specified, it defaults to -1 (i.e.,
// geometric increase beginning at 1).
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Handling Database Queries
/// - - - - - - - - - - - - - - - - - -
// In this example, we simulate a database server accepting queries from
// clients and executing each query in a separate thread.  Client requests are
// simulated by function 'getClientQuery' which returns a query to be executed.
// The class 'Query' encapsulates a database query and 'queryFactory' is an
// object of a query factory class 'QueryFactory'.
//..
//  enum {
//      k_CONNECTION_OPEN_TIME  = 100,  // (simulated) time to open a
//                                      // connection (in microseconds)
//
//      k_CONNECTION_CLOSE_TIME = 8,    // (simulated) time to close a
//                                      // connection (in microseconds)
//
//      k_QUERY_EXECUTION_TIME  = 4     // (simulated) time to execute a query
//                                      // (in microseconds)
//  };
//
//  class my_DatabaseConnection
//      // This class simulates a database connection.
//  {
//    public:
//      my_DatabaseConnection()
//      {
//          bslmt::ThreadUtil::microSleep(k_CONNECTION_OPEN_TIME);
//      }
//
//      ~my_DatabaseConnection()
//      {
//          bslmt::ThreadUtil::microSleep(k_CONNECTION_CLOSE_TIME);
//      }
//
//      void executeQuery(Query *query)
//      {
//          bslmt::ThreadUtil::microSleep(k_QUERY_EXECUTION_TIME);
//          (void)query;
//      }
//  };
//..
// The server runs several threads which, on each iteration, obtain a new
// client request from the query factory, and process it, until the desired
// total number of requests is achieved.
//..
//  extern "C" void serverThread(bsls::AtomicInt *queries,
//                               int              max,
//                               void             (*queryHandler)(Query*))
//  {
//      while (++(*queries) <= max) {
//          Query *query = queryFactory->createQuery();
//          queryHandler(query);
//      }
//  }
//..
// We first give an implementation that does not uses the object pool.  Later
// we will give an implementation using an object pool to manage the database
// connections.  We also keep track of total response time for each case.  When
// object pool is *not* used, each thread, in order to execute a query, creates
// a *new* database connection, calls its 'executeQuery' method to execute the
// query and finally closes the connection.
//..
//  extern "C" void queryHandler1(Query *query)
//      // Handle the specified 'query' without using an objectpool.
//  {
//      bsls::Types::Int64 t1 = bsls::TimeUtil::getTimer();
//      my_DatabaseConnection connection;
//      connection.executeQuery(query);
//      bsls::Types::Int64 t2 = bsls::TimeUtil::getTimer();
//
//      totalResponseTime1 += t2 - t1;
//
//      queryFactory->destroyQuery(query);
//
//      // 'connection' is implicitly destroyed on function return.
//  }
//..
// The main thread starts and joins these threads:
//..
//  enum {
//      k_NUM_THREADS = 8,
//      k_NUM_QUERIES = 10000
//  };
//
//  bsls::AtomicInt numQueries(0);
//  bslmt::ThreadGroup tg;
//
//  tg.addThreads(bdlf::BindUtil::bind(&serverThread,
//                                     &numQueries,
//                                     static_cast<int>(k_NUM_QUERIES),
//                                     &queryHandler1),
//                k_NUM_THREADS);
//  tg.joinAll();
//..
// In above strategy, clients always incur the delay associated with opening
// and closing a database connection.  Now we show an implementation that will
// use object pool to *pool* the database connections.
//
///Object Pool Creation and Functor Argument
///- - - - - - - - - - - - - - - - - - - - -
// In order to create an object pool, we may specify, at construction time, a
// functor encapsulating object creation.  The pool invokes this functor to
// create an object in a memory location supplied by the allocator specified at
// construction and owned by the pool.  By default, the creator invokes the
// default constructor of the underlying type, passing the pool's allocator if
// the type uses the bslma::Allocator protocol to supply memory (as specified
// by the "Uses Bslma Allocator" trait, see 'bslalg_typetraits').  If this
// behavior is not sufficient, we can supply our own functor for type creation.
//
///Creating an Object Pool that Constructs Default Objects
///- - - - - - - - - - - - - - - - - - - - - - - - - - - -
// When the default constructor of our type is sufficient, whether or not that
// type uses 'bslma::Allocator', we can simply use the default behavior of
// 'bdlcc::ObjectPool':
//..
//  bdlcc::ObjectPool<my_DatabaseConnection> pool(-1);
//..
//
///Creating an Object Pool that Constructs Non-Default Objects
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, if we decide that connection IDs must be supplied to
// objects allocated from the pool, we must define a function which invokes
// placement new appropriately.  When using a custom creator functor, it is the
// responsibility of client code to pass the pool's allocator (supplied as the
// second argument to the functor) to the new object if it uses
// bslma::Allocator.
//..
//    void createConnection(void *arena, bslma::Allocator *alloc, int id)
//    {
//       new (arena) my_DatabaseConnection(id, alloc);
//    }
//..
// then...
//..
//    int myId = 100;
//    bdlcc::ObjectPool<my_DatabaseConnection> pool(
//                             bdlf::BindUtil::bind(&createConnection,
//                                                 bdlf::PlaceHolders::_1,
//                                                 bdlf::PlaceHolders::_2,
//                                                 myId));
//..
// Whichever creator we choose, the modified server looks like
//..
//  connectionPool = &pool;
//
//  for (int i = 0; i < k_NUM_QUERIES; ++i) {
//      my_Query *query = getClientQuery();
//      bslmt::ThreadUtil::create(&threads[i], queryHandler2, (void *)query);
//  }
//  for (int i = 0; i < k_NUM_QUERIES; ++i) {
//      bslmt::ThreadUtil::join(threads[i]);
//  }
//..
//
///Modified 'queryHandler'
///- - - - - - - - - - - -
// Now each thread, instead of creating a new connection, gets a connection
// from the object pool.  After using the connection, the client returns it
// back to the pool for further reuse.  The modified 'queryHandler' is
// following.
//..
//    bdlcc::ObjectPool<my_DatabaseConnection> *connectionPool;
//
//    void queryHandler2(Query *query)
//        // Process the specified 'query'.
//    {
//        bsls::Types::Int64 t1 = bsls::TimeUtil::getTimer();
//        my_DatabaseConnection *connection = connectionPool->getObject();
//        connection->executeQuery(query);
//        bsls::Types::Int64 t2 = bsls::TimeUtil::getTimer();
//
//        totalResponseTime2 += t2 - t1;
//
//        connectionPool->releaseObject(connection);
//        queryFactory->destroyQuery(query);
//    }
//..
// The total response time for each strategy is:
//..
// totalResponseTime1 = 199970775520
// totalResponseTime2 = 100354490480
//..

#include <bdlscm_version.h>

#include <bdlma_factory.h>
#include <bdlma_infrequentdeleteblocklist.h>

#include <bslalg_scalarprimitives.h>

#include <bslma_allocator.h>
#include <bslma_default.h>
#include <bslma_destructionutil.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_nestedtraitdeclaration.h>

#include <bslmt_lockguard.h>
#include <bslmt_mutex.h>
#include <bslmt_threadutil.h>

#include <bsls_alignmentfromtype.h>
#include <bsls_assert.h>
#include <bsls_atomic.h>
#include <bsls_atomicoperations.h>
#include <bsls_objectbuffer.h>
#include <bsls_performancehint.h>
#include <bsls_review.h>

#include <bsl_climits.h>
#include <bsl_functional.h>
#include <bsl_memory.h>

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bslalg_typetraits.h>
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

namespace BloombergLP {
namespace bdlcc {

                         // =========================
                         // struct ObjectPoolFunctors
                         // =========================

struct ObjectPoolFunctors {
    // This struct provides several functors that are suitable 'RESETTER'
    // parameter types for 'ObjectPool'.  It also provides a 'typedef' that
    // specifies the default 'CREATOR' parameter type for 'ObjectPool'.

    // PUBLIC TYPES
    typedef bsl::function<void(void *, bslma::Allocator *)> DefaultCreator;
        // The default 'CREATOR' parameter type for the 'ObjectPool' class
        // template.

    template <class TYPE>
    class Nil {
        // This fully-inlined class, suitable as the 'RESETTER' parameter type
        // for 'ObjectPool', is a functor taking a pointer to the parameterized
        // 'TYPE' argument, and can be invoked as: 'void(*)(TYPE*)'.  It does
        // nothing.

      public:
        // Use compiler-generated constructors.

        void operator()(TYPE *object) const;
            // Inlined no-op function.
    };

    template <class TYPE>
    class Reset {
        // This fully-inlined class, suitable as the 'RESETTER' parameter type
        // for 'ObjectPool', is a functor taking a pointer to the parameterized
        // 'TYPE' argument, and can be invoked as: 'void(*)(TYPE*)'.  It calls
        // 'reset' upon the provided object.

      public:
        // Use compiler-generated constructors.

        void operator()(TYPE *object) const;
            // Inlined call to 'object->reset()'.
    };

    template <class TYPE>
    class Clear {
        // This fully-inlined class, suitable as the 'RESETTER' parameter type
        // for 'ObjectPool', is a functor taking a pointer to the parameterized
        // 'TYPE' argument, and can be invoked as: 'void(*)(TYPE*)'.  It calls
        // 'clear' upon the provided object.

      public:
        // Use compiler-generated constructors.

        void operator()(TYPE *object) const;
            // Inlined call to 'object->clear()'.
    };

    template <class TYPE>
    class RemoveAll {
        // This fully-inlined class, suitable as the 'RESETTER' parameter type
        // for 'ObjectPool', is a functor taking a pointer to the parameterized
        // 'TYPE' argument, and can be invoked as: 'void(*)(TYPE*)'.  It calls
        // 'removeAll' upon the provided object.

      public:
        // Use compiler-generated constructors.

        void operator()(TYPE *object) const;
            // Inlined call to 'object->removeAll()'.
    };

};

                     // =================================
                     // class ObjectPool_CreatorConverter
                     // =================================

template <class TYPE, class OTHERTYPE>
class ObjectPool_CreatorConverter {
    // The purpose of this private class is to avoid ambiguity between
    // different template instantiations of 'bsl::function' accepted by the
    // constructors of 'ObjectPool'.  It should not be used directly.
    //
    // This version of the converter ignores the parameterized 'OTHERTYPE'.  It
    // requires a reference to an object of the parameterized 'TYPE' in its
    // constructor.

    // DATA
    const TYPE& d_creator;

  public:
    // CREATORS
    ObjectPool_CreatorConverter(const TYPE& creator);

    // ACCESSORS
    const TYPE& creator() const;
};

template <>
class ObjectPool_CreatorConverter<ObjectPoolFunctors::DefaultCreator,
                                  bsl::function<void(void *)> > {
    // The purpose of this private class is to avoid ambiguity between
    // different template instantiations of bsl::function accepted by the
    // constructors of 'ObjectPool'.  It should not be used directly.
    //
    // This version of the converter is a full template specialization for the
    // case that the default creator type is used with a unary creator.  In
    // this case, 'creator' will return a binder (see 'bdlf_bind') that adapts
    // the unary creator to a binary creator that discards the second argument.
    // This usage is *DEPRECATED* and provided only for backward compatibility.

    // DATA
    const bsl::function<void(void *)>& d_creator;

  public:
    // CREATORS
    ObjectPool_CreatorConverter(const bsl::function<void(void *)>& creator);

    // ACCESSORS
    ObjectPoolFunctors::DefaultCreator creator() const;
};

                       // =============================
                       // class ObjectPool_GeneralProxy
                       // =============================

template <class TYPE>
class ObjectPool_GeneralProxy {
    // This private class template provides a default constructor which simply
    // invokes the default constructor of the parameterized 'TYPE'.

    // DATA
    bsls::ObjectBuffer<TYPE> d_object;

    // NOT IMPLEMENTED
    ObjectPool_GeneralProxy& operator=(const ObjectPool_GeneralProxy&);
    ObjectPool_GeneralProxy(const ObjectPool_GeneralProxy&);

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(ObjectPool_GeneralProxy,
                                   bslma::UsesBslmaAllocator);

    // CREATORS
    explicit
    ObjectPool_GeneralProxy(bslma::Allocator *basicAllocator);
        // Create a new proxy and a new object of the parameterized 'TYPE'.  If
        // 'TYPE' declares the "Uses Allocator" trait, the specified
        // 'basicAllocator' is supplied to its default constructor; otherwise
        // 'basicAllocator' is ignored.

    ObjectPool_GeneralProxy(const TYPE&       other,
                            bslma::Allocator *basicAllocator);
        // Create a new proxy and a new object constructed from the specified
        // 'other' object.  If 'TYPE' declares the "Uses Allocator" trait, the
        // specified 'basicAllocator' is supplied to its copy constructor;
        // otherwise 'basicAllocator' is ignored.

    ~ObjectPool_GeneralProxy();
        // Destroy this proxy and the underlying object.

    // MANIPULATORS
    TYPE& object();
        // Return a reference to the modifiable object held by this proxy.
};

                       // =============================
                       // class ObjectPool_DefaultProxy
                       // =============================

// SPECIALIZATIONS
template <class TYPE>
class ObjectPool_DefaultProxy {
    // This private class template provides a default constructor that creates
    // a proxied 'bsl::function' object that invokes the default constructor of
    // the parameterized 'TYPE' with placement 'new'.

    // PRIVATE TYPES
    typedef ObjectPoolFunctors::DefaultCreator Creator;

    // DATA
    Creator d_object;

    // NOT IMPLEMENTED
    ObjectPool_DefaultProxy(const ObjectPool_DefaultProxy&);
    ObjectPool_DefaultProxy& operator=(const ObjectPool_DefaultProxy&);

  private:
    // PRIVATE CLASS METHODS
    static void defaultConstruct(void *arena, bslma::Allocator *allocator);
        // Invoke, with the specified 'arena' and 'allocator',
        // 'bslalg::ScalarPrimitives::defaultConstruct(arena, allocator)'.
        // This method is necessary to select the correct overload for TYPE.

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(ObjectPool_DefaultProxy,
                                   bslma::UsesBslmaAllocator);

    // CREATORS
    explicit
    ObjectPool_DefaultProxy(bslma::Allocator *basicAllocator);
        // Create a new proxy for a function object which invokes the default
        // constructor of TYPE.  Use the specified 'basicAllocator' to supply
        // memory.

    ObjectPool_DefaultProxy(const Creator&    rhs,
                            bslma::Allocator *basicAllocator);
        // Create a proxy for a newly created function object constructed from
        // the specified 'rhs' creator.  Use the specified 'basicAllocator' to
        // supply memory.

    ~ObjectPool_DefaultProxy();
        // Destroy this proxy and the underlying object.

    // MANIPULATORS
    Creator& object();
        // Return a reference to the modifiable function object held by this
        // proxy.
};

                        // ============================
                        // class ObjectPool_ProxyPicker
                        // ============================
template <class CREATOR>
struct ObjectPool_ProxyPicker {
    // For a 'CREATOR' type other than the specialization below, provide a
    // metafunction that returns 'ObjectPool_GeneralProxy<CREATOR>' as the
    // creator proxy for all types.
    template <class TYPE>
    struct Selector {
        typedef ObjectPool_GeneralProxy<CREATOR> Proxy;
    };
};

template <>
struct ObjectPool_ProxyPicker<ObjectPoolFunctors::DefaultCreator>
{
    // For the ObjectPoolFunctors::DefaultCreator, provide a metafunction that
    // returns 'ObjectPool_DefaultProxy<TYPE>' as the creator proxy for type
    // 'TYPE'.
    template <class TYPE>
    struct Selector
    {
        typedef ObjectPool_DefaultProxy<TYPE> Proxy;
    };
};
                              // ================
                              // class ObjectPool
                              // ================

template <class TYPE,
          class CREATOR  = ObjectPoolFunctors::DefaultCreator,
          class RESETTER = ObjectPoolFunctors::Nil<TYPE> >
class ObjectPool : public bdlma::Factory<TYPE> {
    // This class provides a thread-safe pool of reusable objects.  It also
    // implements the 'bdlma::Factory' protocol: "creating" objects gets them
    // from the pool and "deleting" objects returns them to the pool.

    // PRIVATE TYPES
    typedef ObjectPool<TYPE, CREATOR, RESETTER> MyType;

    union ObjectNode {
        // This class stores a list pointer for linking the object nodes
        // together in the free objects list, in which case the reference count
        // is 0.  The list pointer is set to 0 when the reference count is not
        // 0, although that is not necessary.  A negative reference count
        // indicates a node which does not contain an initialized object (the
        // object was destroyed and the creator threw before node could be
        // released again).

        struct {
            ObjectNode                               *d_next_p;
            bsls::AtomicOperations::AtomicTypes::Int  d_refCount;
        } d_inUse;
        typename bsls::AlignmentFromType<TYPE>::Type d_dummy;
                                     // padding provider for proper alignment
                                     // of 'TYPE' objects
    };

    union BlockNode {
        // This class stores information about a block, which is organized as a
        // 'BlockNode' followed by 'd_numObjects' frames, each containing an
        // 'ObjectNode' followed by a 'TYPE', all of it suitably aligned.

        struct {
            BlockNode *d_next_p;
            int        d_numObjects; // number of objects in this block
        } d_inUse;
        typename bsls::AlignmentFromType<ObjectNode>::Type d_dummy;
                                     // padding provider for proper alignment
                                     // of 'ObjectNode'
    };

    class AutoCleanup {
        // This class, private to ObjectPool, implements a proctor for objects
        // created and stored into a temporary list of object nodes as in the
        // 'ObjectPool' type, used in the replenishing method called from
        // 'getObject', 'reserveCapacity' and 'increaseCapacity', to ensure the
        // exception-neutrality with full rollback guarantees of the object
        // pool.

      public:
        // TYPES
        typedef typename ObjectPool<TYPE, CREATOR, RESETTER>::ObjectNode
                                                                    ObjectNode;
        typedef typename ObjectPool<TYPE, CREATOR, RESETTER>::BlockNode
                                                                    BlockNode;

      private:
        // DATA
        BlockNode                        *d_block_p;      // held, not owned
        ObjectNode                       *d_head_p;       // held, not owned
        bdlma::InfrequentDeleteBlockList *d_allocator_p;  // held, not owned
        int                               d_numNodes;

      public:
        // CREATORS
        AutoCleanup(BlockNode                        *block,
                    ObjectNode                       *head,
                    bdlma::InfrequentDeleteBlockList *allocator,
                    int                               numNodes = 0);
            // Create a proctor for the list of the optionally specified
            // 'numNodes' number of nodes with the specified 'head', using the
            // 'allocator' to deallocate the block starting at the specified
            // 'block' at destruction after all the objects in the list have
            // been destroyed, unless the 'release' method has been called.

        ~AutoCleanup();
            // Destroy this object, using the 'allocator' to deallocate the
            // block under management at destruction after all the objects
            // under management in the list have been destroyed, unless the
            // 'release' method has been called.

        // MANIPULATORS
        AutoCleanup& operator++();
            // Increment the number of nodes under management.  Nodes are added
            // sequentially in the list.

        void release();
            // Release the currently held list of nodes from management by this
            // proctor.
    };

    enum {
        // A block containing 'N' objects is organized with a single
        // 'BlockNode' followed by 'N' frames, each frame consisting of one
        // 'ObjectNode' and a 'TYPE', all suitably aligned.  The following
        // constants describe the size of a frame in terms of its multiple of
        // 'sizeof(ObjectNode)'.  We choose 'sizeof(ObjectNode)' as the basic
        // unit because it lets us do pointer arithmetic on 'ObjectNode *' more
        // easily.

        k_ROUNDED_NUM_OBJECTS = (sizeof(TYPE) + sizeof(ObjectNode) - 1) /
                                                            sizeof(ObjectNode),
                                     // number of 'ObjectNode' needed to
                                     // contain an object of 'TYPE' (rounded up
                                     // to the next integer)

        k_NUM_OBJECTS_PER_FRAME = 1 + k_ROUNDED_NUM_OBJECTS,
                                     // number of 'ObjectNode' equivalent (in
                                     // size) to a frame (object node followed
                                     // by 'TYPE')

        k_MAX_NUM_OBJECTS_PER_FRAME = (INT_MAX / sizeof(ObjectNode) - 1) /
                                                        k_NUM_OBJECTS_PER_FRAME
                                     // 'N' must be less than this
                                     // 'k_MAX_NUM_OBJECTS_PER_FRAME' so that
                                     // the number of bytes in a block, which
                                     // is '(1 + N * NUM_OBJECTS_PER_FRAME)'
                                     // times 'sizeof(ObjectNode)', does not
                                     // overflow
    };

    enum {
        // Default configuration parameters.  Adjust these to tune up
        // performance of 'ObjectPool'.

        k_GROW_FACTOR           =   2,  // multiplicative factor to grow
                                        // capacity

        k_MAX_NUM_OBJECTS       = -32   // minimum 'd_numReplenishObjects'
                                        // value beyond which
                                        // 'd_numReplenishObjects' becomes
                                        // positive
    };

    // DATA
    bsls::AtomicPointer<ObjectNode>
                           d_freeObjectsList;      // list of free objects

    typename ObjectPool_ProxyPicker<CREATOR>::template Selector<TYPE>::Proxy
                           d_objectCreator;        // functor for object
                                                   // creation

    bslalg::ConstructorProxy<RESETTER>
                           d_objectResetter;       // functor to reset object

    int                    d_numReplenishObjects;  // pool growth behavior
                                                   // option (see above)

    bsls::AtomicInt        d_numAvailableObjects;  // number of available
                                                   // objects

    bsls::AtomicInt        d_numObjects;           // number of objects created
                                                   // by this pool

    BlockNode             *d_blockList;            // list of memory blocks

    bdlma::InfrequentDeleteBlockList
                           d_blockAllocator;       // memory block supplier

    bslma::Allocator      *d_allocator_p;          // held, not owned

    bslmt::Mutex           d_mutex;                // pool replenishment
                                                   // serializer

    // NOT IMPLEMENTED
    ObjectPool(const MyType&, bslma::Allocator * = 0);
    ObjectPool& operator=(const MyType&);

    // FRIENDS
    friend class AutoCleanup;

  private:
    // PRIVATE MANIPULATORS
    void replenish();
        // Add additional objects to this pool based on the replenishment
        // policy specified by the 'growBy' argument at construction.

    void addObjects(int numObjects);
        // Create the specified 'numObjects' objects and attach them to this
        // object pool.

  public:
    // TYPES
    typedef RESETTER ResetterType;
    typedef CREATOR  CreatorType;

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(ObjectPool, bslma::UsesBslmaAllocator);

    // CREATORS
    explicit
    ObjectPool(int               growBy = -1,
               bslma::Allocator *basicAllocator = 0);
        // Create an object pool that invokes the default constructor of the
        // the parameterized 'TYPE' to construct objects.  When the pool is
        // depleted, it will increase its capacity according to the optionally
        // specified 'growBy' value.  If 'growBy' is positive, the pool
        // replenishes itself with at least 'growBy' new objects.  If 'growBy'
        // is negative, the amount of increase begins at '-growBy' and grows
        // geometrically up to an implementation-defined maximum.  When objects
        // are returned to the pool, the default value of RESETTER is invoked
        // with a pointer to the returned object to restore the object to a
        // reusable state.  Optionally specify a 'basicAllocator' used to
        // supply memory.  If 'basicAllocator' is 0, the currently installed
        // default allocator is used.  The behavior is undefined unless
        // '0 != growBy'.

    explicit
    ObjectPool(const CREATOR&    objectCreator,
               int               growBy,
               bslma::Allocator *basicAllocator = 0);
    explicit
    ObjectPool(const CREATOR&    objectCreator,
               bslma::Allocator *basicAllocator = 0);
        // Create an object pool that uses the specified 'objectCreator'
        // (encapsulating the construction of objects) to create objects.  The
        // client must ensure that 'objectCreator(buf, alloc)' creates an
        // object at memory location 'buf' using 'alloc' to supply memory.
        // When the pool is depleted, it will grow capacity according to the
        // optionally specified 'growBy' value.  If 'growBy' is positive, the
        // pool replenishes itself with at least 'growBy' new objects.  If
        // 'growBy' is negative, the amount of increase begins at '-growBy' and
        // grows geometrically up to an implementation-defined maximum.  When
        // objects are returned to the pool, the default value of RESETTER is
        // invoked with a pointer to the returned object to restore the object
        // to a reusable state.  Optionally specify a 'basicAllocator' used to
        // supply memory.  If 'basicAllocator' is 0, the currently installed
        // default allocator is used.  The behavior is undefined unless
        // '0 != growBy'.

    ObjectPool(const CREATOR&    objectCreator,
               const RESETTER&   objectResetter,
               int               growBy = -1,
               bslma::Allocator *basicAllocator = 0);
        // Create an object pool that uses the specified 'objectCreator'
        // (encapsulating the construction of objects) to create objects.  The
        // client must ensure that 'objectCreator(buf, alloc)' creates an
        // object at memory location 'buf' using 'alloc' to supply memory.
        // When the pool is depleted, it will increase its capacity according
        // to the optionally specified 'growBy' value.  If 'growBy' is
        // positive, the pool replenishes itself with at least 'growBy' new
        // objects.  If 'growBy' is negative, the amount of increase begins at
        // '-growBy' and grows geometrically up to an implementation-defined
        // maximum.  When objects are returned to the pool, the specified
        // 'objectResetter' is invoked with a pointer to the returned object to
        // restore the object to a reusable state.  Optionally specify a
        // 'basicAllocator' used to supply memory.  If 'basicAllocator' is 0,
        // the currently installed default allocator is used.  The behavior is
        // undefined unless '0 != growBy'.

    template <class ANYPROTO>
    explicit
    ObjectPool(const bsl::function<ANYPROTO>&  objectCreator,
               int                             growBy,
               bslma::Allocator               *basicAllocator = 0);
    template <class ANYPROTO>
    explicit
    ObjectPool(const bsl::function<ANYPROTO>&  objectCreator,
               bslma::Allocator               *basicAllocator = 0);
        // *DEPRECATED* Use a creator of the parameterized 'CREATOR' type.

    virtual ~ObjectPool();
        // Destroy this object pool.  All objects created by this pool are
        // destroyed (even if some of them are still in use) and memory is
        // reclaimed.

    // MANIPULATORS
    TYPE *getObject();
        // Return an address of modifiable object from this object pool.  If
        // this pool is empty, it is replenished according to the strategy
        // specified at the pool construction (or an implementation-defined
        // strategy if none was provided).

    void increaseCapacity(int numObjects);
        // Create the specified 'numObjects' objects and add them to this
        // object pool.  The behavior is undefined unless '0 <= numObjects'.

    void releaseObject(TYPE *object);
        // Return the specified 'object' back to this object pool.  Invoke the
        // RESETTER specified at construction, or the default RESETTER if none
        // was provided, before making the object available for reuse.  Note
        // that if RESETTER is the default type ('ObjectPoolFunctors::Nil'),
        // then this method should be invoked to return only *valid* objects
        // because the pool uses the released objects to satisfy further
        // 'getObject' requests.  The behavior is undefined unless the 'object'
        // was obtained from this object pool's 'getObject' method and is not
        // already in a released state.

    void reserveCapacity(int numObjects);
        // Create enough objects to satisfy requests for at least the specified
        // 'numObjects' objects before the next replenishment.  The behavior is
        // undefined unless '0 <= numObjects'.  Note that this method is
        // different from 'increaseCapacity' in that the number of created
        // objects may be less than 'numObjects'.

    // ACCESSORS
    int numAvailableObjects() const;
        // Return a *snapshot* of the number of objects available in this pool.

    int numObjects() const;
        // Return the (instantaneous) number of objects managed by this pool.
        // This includes both the objects available in the pool and the objects
        // that were allocated from the pool and not yet released.

    // 'bdlma::Factory' INTERFACE
    virtual TYPE *createObject();
        // This concrete implementation of 'bdlma::Factory::createObject'
        // invokes 'getObject'.  This should not be invoked directly.

    virtual void deleteObject(TYPE *object);
        // This concrete implementation of 'bdlma::Factory::deleteObject'
        // invokes 'releaseObject' on the specified 'object', returning it to
        // this pool.  The behavior is undefined if 'object' is already in a
        // released state.  Note that this does *not* destroy the object and
        // should not be invoked directly.
};

// ============================================================================
//                            INLINE DEFINITIONS
// ============================================================================

                                // ----------
                                // ObjectPool
                                // ----------

// PRIVATE MANIPULATORS
template <class TYPE, class CREATOR, class RESETTER>
void ObjectPool<TYPE, CREATOR, RESETTER>::replenish()
{
    int numObjects = d_numReplenishObjects >= 0
                   ? d_numReplenishObjects
                   : -d_numReplenishObjects;
    addObjects(numObjects);

    // Grow pool capacity only if 'd_numReplenishObjects' is negative and
    // greater than 'k_MAX_NUM_OBJECTS' (i.e., if the absolute value of
    // 'numObjects' is less than 'k_MAX_NUM_OBJECTS').

    if (d_numReplenishObjects < 0) {
        if (d_numReplenishObjects > k_MAX_NUM_OBJECTS) {
            d_numReplenishObjects *= k_GROW_FACTOR;
        }
        else {
            d_numReplenishObjects = -d_numReplenishObjects;
        }
    }
}

template <class TYPE, class CREATOR, class RESETTER>
void ObjectPool<TYPE, CREATOR, RESETTER>::addObjects(int numObjects)
{
    // Allocate a single memory block to be used for creating block nodes,
    // object nodes, and objects.  Too large a value for 'numObjects' would
    // cause overflow in 'NUM_BYTES_PER_BLOCK' below.

    BSLS_ASSERT(numObjects <= k_MAX_NUM_OBJECTS_PER_FRAME);

    const int NUM_BYTES_PER_BLOCK = (int)(sizeof(BlockNode) +
                                          sizeof(ObjectNode) * numObjects *
                                                   k_NUM_OBJECTS_PER_FRAME);

    BlockNode *start = (BlockNode *) d_blockAllocator.allocate(
                                                          NUM_BYTES_PER_BLOCK);

    // Create a block node

    start->d_inUse.d_next_p = d_blockList;
    start->d_inUse.d_numObjects = numObjects;

    // Create and link 'numObjects' objects

    ObjectNode *last = (ObjectNode *)(start + 1);
    AutoCleanup startGuard(start, last, &d_blockAllocator, 0);

    for (int i = 0; i < numObjects; ++i, ++startGuard) {
        last->d_inUse.d_next_p = last + k_NUM_OBJECTS_PER_FRAME;
        bsls::AtomicOperations::initInt(&last->d_inUse.d_refCount, 0);
        d_objectCreator.object()(last + 1, d_allocator_p);
        last += k_NUM_OBJECTS_PER_FRAME;
    }
    last -= k_NUM_OBJECTS_PER_FRAME;
    bsls::AtomicOperations::initInt(&last->d_inUse.d_refCount, 0);

    // If all went well (no exceptions), attach it to 'd_blockList'

    startGuard.release();
    d_blockList = start;

    // Attach the created objects to 'd_freeObjectsList'

    ++start;
    ObjectNode *old;
    do {
        old = d_freeObjectsList;
        last->d_inUse.d_next_p = old;
    } while (old != d_freeObjectsList.testAndSwap(old, (ObjectNode *)start));

    d_numObjects.addRelaxed(numObjects);
    d_numAvailableObjects.addRelaxed(numObjects);
}

// CREATORS
template <class TYPE, class CREATOR, class RESETTER>
ObjectPool<TYPE, CREATOR, RESETTER>::ObjectPool(
                                              int               growBy,
                                              bslma::Allocator *basicAllocator)
: d_freeObjectsList(0)
, d_objectCreator(basicAllocator)
, d_objectResetter(basicAllocator)
, d_numReplenishObjects(growBy)
, d_blockList(0)
, d_blockAllocator(basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
    BSLS_ASSERT(0 != d_numReplenishObjects);
}

template <class TYPE, class CREATOR, class RESETTER>
ObjectPool<TYPE, CREATOR, RESETTER>::ObjectPool(
                                              const CREATOR&    objectCreator,
                                              int               growBy,
                                              bslma::Allocator *basicAllocator)
: d_freeObjectsList(0)
, d_objectCreator(objectCreator, basicAllocator)
, d_objectResetter(basicAllocator)
, d_numReplenishObjects(growBy)
, d_blockList(0)
, d_blockAllocator(basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
    BSLS_ASSERT(0 != d_numReplenishObjects);
}

template <class TYPE, class CREATOR, class RESETTER>
inline
ObjectPool<TYPE, CREATOR, RESETTER>::ObjectPool(
                                              const CREATOR&    objectCreator,
                                              bslma::Allocator *basicAllocator)
: d_freeObjectsList(0)
, d_objectCreator(objectCreator, basicAllocator)
, d_objectResetter(basicAllocator)
, d_numReplenishObjects(-1)
, d_blockList(0)
, d_blockAllocator(basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
    BSLS_ASSERT(0 != d_numReplenishObjects);
}

template <class TYPE, class CREATOR, class RESETTER>
template <class ANYPROTO>
ObjectPool<TYPE, CREATOR, RESETTER>::ObjectPool(
                                const bsl::function<ANYPROTO>&  objectCreator,
                                bslma::Allocator               *basicAllocator)
: d_freeObjectsList(0)
, d_objectCreator(
      ObjectPool_CreatorConverter<CREATOR, bsl::function<ANYPROTO> >(
                                                      objectCreator).creator(),
      basicAllocator)
, d_objectResetter(basicAllocator)
, d_numReplenishObjects(-1)
, d_blockList(0)
, d_blockAllocator(basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
    BSLS_ASSERT(0 != d_numReplenishObjects);
}

template <class TYPE, class CREATOR, class RESETTER>
template <class ANYPROTO>
ObjectPool<TYPE, CREATOR, RESETTER>::ObjectPool(
                                const bsl::function<ANYPROTO>&  objectCreator,
                                int                             growBy,
                                bslma::Allocator               *basicAllocator)
: d_freeObjectsList(0)
, d_objectCreator(
      ObjectPool_CreatorConverter<CREATOR, bsl::function<ANYPROTO> >(
                                                      objectCreator).creator(),
      basicAllocator)
, d_objectResetter(basicAllocator)
, d_numReplenishObjects(growBy)
, d_blockList(0)
, d_blockAllocator(basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
    BSLS_ASSERT(0 != d_numReplenishObjects);
}

template <class TYPE, class CREATOR, class RESETTER>
ObjectPool<TYPE, CREATOR, RESETTER>::ObjectPool(
                                              const CREATOR&    objectCreator,
                                              const RESETTER&   objectResetter,
                                              int               growBy,
                                              bslma::Allocator *basicAllocator)
: d_freeObjectsList(0)
, d_objectCreator(objectCreator, basicAllocator)
, d_objectResetter(objectResetter, basicAllocator)
, d_numReplenishObjects(growBy)
, d_blockList(0)
, d_blockAllocator(basicAllocator)
, d_allocator_p(bslma::Default::allocator(basicAllocator))
{
    BSLS_ASSERT(0 != d_numReplenishObjects);
}

template <class TYPE, class CREATOR, class RESETTER>
ObjectPool<TYPE, CREATOR, RESETTER>::~ObjectPool()
{
    // Traverse the 'd_blockList', destroying all the objects associated with
    // each block, irrespective of whether their reference count is zero or
    // not.

    for (; d_blockList; d_blockList = d_blockList->d_inUse.d_next_p) {
        int numObjects = d_blockList->d_inUse.d_numObjects;
        ObjectNode *p = (ObjectNode *)(d_blockList + 1);
        for (; numObjects != 0; --numObjects) {
           ((TYPE *)(p + 1))->~TYPE();
            p += k_NUM_OBJECTS_PER_FRAME;
      }
  }
}

// MANIPULATORS
template <class TYPE, class CREATOR, class RESETTER>
TYPE *ObjectPool<TYPE, CREATOR, RESETTER>::getObject()
{
    ObjectNode *p;
    do {
        p = d_freeObjectsList.loadAcquire();
        if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!p)) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;

            bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
            p = d_freeObjectsList;
            if (!p) {
                replenish();
                continue;
            }
        }
        if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(
            2 != bsls::AtomicOperations::addIntNv(&p->d_inUse.d_refCount,2))) {
            BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
            for (int i = 0; i < 3; ++i) {
                // To avoid unnecessary contention, assume that if we did not
                // get the first reference, then the other thread is about to
                // complete the pop.  Wait for a few cycles until he does.  If
                // he does not complete then go on and try to acquire it
                // ourselves.

                if (d_freeObjectsList != p) {
                    break;
                }
            }
        }

        // Force a dependent read of d_next_p to make sure that we're not
        // racing against a thread calling 'deallocate' for 'p' and that
        // checked the 'refCount' *before* we incremented it.  Either we can
        // observe the new free list value (== p) and because of the release
        // barrier, we can observe the new 'd_next_p' value (this relies on a
        // dependent load) or 'loadRelaxed' will the "old" (!= p) and the
        // condition will fail.  Note that 'h' is made volatile so that the
        // compiler does not replace the 'h->d_inUse' load with 'p->d_inUse'
        // (and thus removing the data dependency).  TBD to be completely
        // thorough 'h->d_inUse.d_next_p' needs a load dependent barrier (no-op
        // on all current architectures though).

        const ObjectNode * volatile h = d_freeObjectsList.loadRelaxed();

        // Split the likely into 2 to workaround gcc 4.2 to gcc 4.4 bugs
        // documented in 'bsls_performancehint'.

        if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(h == p)
         && BSLS_PERFORMANCEHINT_PREDICT_LIKELY(
                  d_freeObjectsList.testAndSwap(p,h->d_inUse.d_next_p) == p)) {
            break;
        }

        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;

        int refCount;
        for (;;) {
            refCount = bsls::AtomicOperations::getInt(&p->d_inUse.d_refCount);

            if (refCount & 1) {
                // The node is now free but not on the free list.  Try to take
                // it.

                if (refCount == bsls::AtomicOperations::testAndSwapInt(
                                                    &p->d_inUse.d_refCount,
                                                    refCount,
                                                    refCount^1)) {
                    // Taken!
                    p->d_inUse.d_next_p = 0;  // not strictly necessary
                    d_numAvailableObjects.addRelaxed(-1);
                    return (TYPE*)(p + 1);                            // RETURN

                }
            }
            else if (refCount == bsls::AtomicOperations::testAndSwapInt(
                                                    &p->d_inUse.d_refCount,
                                                    refCount,
                                                    refCount - 2)) {
                break;
            }
        }
    } while (1);

    p->d_inUse.d_next_p = 0;  // not strictly necessary
    d_numAvailableObjects.addRelaxed(-1);
    return (TYPE *)(p+1);
}

template <class TYPE, class CREATOR, class RESETTER>
void ObjectPool<TYPE, CREATOR, RESETTER>::increaseCapacity(int numObjects)
{
    if (numObjects > 0) {
       bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
       addObjects(numObjects);
    }
}

template <class TYPE, class CREATOR, class RESETTER>
void ObjectPool<TYPE, CREATOR, RESETTER>::releaseObject(TYPE *object)
{
    ObjectNode *current = (ObjectNode *)(void *)object - 1;
    d_objectResetter.object()(object);

    int refCount = bsls::AtomicOperations::getIntRelaxed(
                                                 &current->d_inUse.d_refCount);
    do {
        if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(2 == refCount)) {
            refCount = bsls::AtomicOperations::testAndSwapInt(
                                                  &current->d_inUse.d_refCount,
                                                  2,
                                                  0);
            if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(2 == refCount)) {
                break;
            }
        }

        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;

        const int oldRefCount = refCount;
        refCount = bsls::AtomicOperations::testAndSwapInt(
                                                &current->d_inUse.d_refCount,
                                                refCount,
                                                refCount - 1);
        if (oldRefCount == refCount) {
            // Someone else is still trying to pop this item.  Just let them
            // have it.

            d_numAvailableObjects.addRelaxed(1);
            return;                                                   // RETURN
        }

    } while (1);

    ObjectNode *head = d_freeObjectsList.loadRelaxed();
    for (;;) {
        current->d_inUse.d_next_p = head;
        ObjectNode * const oldHead = head;
        head = d_freeObjectsList.testAndSwap(head, current);
        if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(oldHead == head)) {
            break;
        }
        BSLS_PERFORMANCEHINT_UNLIKELY_HINT;
    }
    d_numAvailableObjects.addRelaxed(1);
}

template <class TYPE, class CREATOR, class RESETTER>
void ObjectPool<TYPE, CREATOR, RESETTER>::reserveCapacity(int numObjects)
{
   bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
   numObjects -= d_numObjects;
   if (numObjects > 0) {
      addObjects(numObjects);
   }
}

// ACCESSORS
template <class TYPE, class CREATOR, class RESETTER>
inline
int ObjectPool<TYPE, CREATOR, RESETTER>::numAvailableObjects() const
{
    return  d_numAvailableObjects;
}

template <class TYPE, class CREATOR, class RESETTER>
inline
int ObjectPool<TYPE, CREATOR, RESETTER>::numObjects() const
{
    return d_numObjects;
}

template <class TYPE, class CREATOR, class RESETTER>
inline
TYPE *ObjectPool<TYPE, CREATOR, RESETTER>::createObject()
{
    return getObject();
}

template <class TYPE, class CREATOR, class RESETTER>
inline
void ObjectPool<TYPE, CREATOR, RESETTER>::deleteObject(TYPE *object)
{
    releaseObject(object);
}

                       // ---------------------------
                       // ObjectPool_CreatorConverter
                       // ---------------------------

// CREATORS
template <class TYPE, class OTHERTYPE>
inline
ObjectPool_CreatorConverter<TYPE, OTHERTYPE>::
ObjectPool_CreatorConverter(const TYPE& creator)
: d_creator(creator)
{
}

template <class TYPE, class OTHERTYPE>
inline
const TYPE& ObjectPool_CreatorConverter<TYPE, OTHERTYPE>
::creator() const
{
    return d_creator;
}

inline
ObjectPool_CreatorConverter<ObjectPoolFunctors::DefaultCreator,
                            bsl::function<void(void *)> >::
ObjectPool_CreatorConverter(const bsl::function<void(void *)>& creator)
: d_creator(creator)
{
}

                         // -----------------------
                         // ObjectPool_DefaultProxy
                         // -----------------------

// CLASS METHODS
template <class TYPE>
inline
void ObjectPool_DefaultProxy<TYPE>
::defaultConstruct(void *arena, bslma::Allocator *allocator)
{
    bslalg::ScalarPrimitives::defaultConstruct((TYPE *)arena, allocator);
}

// CREATORS
template <class TYPE>
inline
ObjectPool_GeneralProxy<TYPE>
::ObjectPool_GeneralProxy(bslma::Allocator *basicAllocator)
{
    bslalg::ScalarPrimitives::defaultConstruct(&d_object.object(),
                                               basicAllocator);
}

template <class TYPE>
inline
ObjectPool_GeneralProxy<TYPE>
::ObjectPool_GeneralProxy(const TYPE& other, bslma::Allocator *basicAllocator)
{
    bslalg::ScalarPrimitives::copyConstruct(&d_object.object(),
                                            other,
                                            basicAllocator);
}

template <class TYPE>
inline
ObjectPool_GeneralProxy<TYPE>
::~ObjectPool_GeneralProxy()
{
    bslma::DestructionUtil::destroy(&d_object.object());
}

template <class TYPE>
inline
ObjectPool_DefaultProxy<TYPE>
::ObjectPool_DefaultProxy(bslma::Allocator *basicAllocator)
: d_object(bsl::allocator_arg_t(),
           bsl::allocator<Creator>(basicAllocator),
           &ObjectPool_DefaultProxy::defaultConstruct)
{
}

template <class TYPE>
inline
ObjectPool_DefaultProxy<TYPE>
::ObjectPool_DefaultProxy(const Creator&    rhs,
                          bslma::Allocator *basicAllocator)
: d_object(bsl::allocator_arg_t(),
           bsl::allocator<Creator>(basicAllocator),
           rhs)
{
}

template <class TYPE>
inline
ObjectPool_DefaultProxy<TYPE>
::~ObjectPool_DefaultProxy()
{
}

// MANIPULATORS
template <class TYPE>
inline
TYPE& ObjectPool_GeneralProxy<TYPE>::object()
{
    return d_object.object();
}

template <class TYPE>
inline
typename ObjectPool_DefaultProxy<TYPE>::Creator&
ObjectPool_DefaultProxy<TYPE>
::object()
{
    return d_object;
}

                     // -------------------------
                     // ObjectPoolFunctors::Reset
                     // -------------------------

// ACCESSORS
template <class TYPE>
inline
void ObjectPoolFunctors::Reset<TYPE>::operator()(TYPE *object) const
{
   object->reset();
}

                      // -----------------------
                      // ObjectPoolFunctors::Nil
                      // -----------------------

// ACCESSORS
template <class TYPE>
inline
void ObjectPoolFunctors::Nil<TYPE>::operator()(TYPE *) const
{
}

                     // -------------------------
                     // ObjectPoolFunctors::Clear
                     // -------------------------

// ACCESSORS
template <class TYPE>
inline
void ObjectPoolFunctors::Clear<TYPE>::operator()(TYPE *object) const
{
   object->clear();
}

                   // -----------------------------
                   // ObjectPoolFunctors::RemoveAll
                   // -----------------------------

// ACCESSORS
template <class TYPE>
inline
void ObjectPoolFunctors::RemoveAll<TYPE>::operator()(TYPE *object) const
{
   object->removeAll();
}

                      // ----------------------
                      // ObjectPool_AutoCleanup
                      // ----------------------

// CREATORS
template <class TYPE, class CREATOR, class RESETTER>
inline
ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup::AutoCleanup(
                                   BlockNode                        *block,
                                   ObjectNode                       *head,
                                   bdlma::InfrequentDeleteBlockList *allocator,
                                   int                               numNodes)
: d_block_p(block)
, d_head_p(head)
, d_allocator_p(allocator)
, d_numNodes(numNodes)
{
}

template <class TYPE, class CREATOR, class RESETTER>
ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup::~AutoCleanup()
{
    enum {
        k_NUM_OBJECTS_PER_FRAME =
           ObjectPool<TYPE, CREATOR, RESETTER>::k_NUM_OBJECTS_PER_FRAME
    };
    if (d_head_p) {
        for (++d_head_p; d_numNodes > 0; --d_numNodes) {
            ((TYPE *)d_head_p)->~TYPE();
            d_head_p += k_NUM_OBJECTS_PER_FRAME;
        }
        d_allocator_p->deallocate(d_block_p);
    }
}

// MANIPULATORS
template <class TYPE, class CREATOR, class RESETTER>
inline
typename ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup&
ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup::operator++()
{
    ++d_numNodes;
    return *this;
}

template <class TYPE, class CREATOR, class RESETTER>
inline
void ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup::release()
{
    d_block_p = 0;
    d_head_p = 0;
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------