// bslstl_bidirectionalnodepool.h                                     -*-C++-*-
#ifndef INCLUDED_BSLSTL_BIDIRECTIONALNODEPOOL
#define INCLUDED_BSLSTL_BIDIRECTIONALNODEPOOL

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

//@PURPOSE: Provide efficient creation of nodes used in a node-based container.
//
//@CLASSES:
//   bslstl::BidirectionalNodePool: memory manager to allocate hash table nodes
//
//@SEE_ALSO: bslstl_simplepool
//
//@DESCRIPTION: This component implements a mechanism, 'BidirectionalNodePool',
// that creates and destroys 'bslalg::BidirectionalListNode' objects holding
// objects of a (template parameter) type 'VALUE' for use in hash-table-based
// containers.
//
// A 'BidirectionalNodePool' uses a memory pool provided by the
// 'bslstl_simplepool' component in its implementation to provide memory for
// the nodes (see 'bslstl_simplepool').
//
///Memory Allocation
///-----------------
// 'BidirectionalNodePool' uses an allocator of the (template parameter) type
// 'ALLOCATOR' specified at construction to allocate memory.
// 'BidirectionalNodePool' supports allocators meeting the requirements of the
// C++ standard allocator requirements ([allocator.requirements], C++11
// 17.6.3.5).
//
// If 'ALLOCATOR' is 'bsl::allocator' and the (template parameter) type 'VALUE'
// defines the 'bslma::UsesBslmaAllocator' trait, then the 'bslma::Allocator'
// object specified at construction will be supplied to constructors of the
// (template parameter) type 'VALUE' in the 'cloneNode' method and
// 'emplaceIntoNewNode' method overloads.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Creating a Linked List Container
///- - - - - - - - - - - - - - - - - - - - - -
// Suppose that we want to define a bidirectional linked list that can hold
// elements of a template parameter type.  'bslstl::BidirectionalNodePool' can
// be used to create and destroy nodes that make up a linked list.
//
// First, we create an elided definition of the class template 'MyList':
//..
// #include <bslalg_bidirectionallinklistutil.h>
//
//  template <class VALUE, class ALLOCATOR>
//  class MyList {
//      // This class template implements a bidirectional linked list of
//      // element of the (template parameter) type 'VALUE'.  The memory used
//      // will be allocated from an allocator of the (template parameter) type
//      // 'ALLOCATOR' specified at construction.
//
//    public:
//      // TYPES
//      typedef bslalg::BidirectionalNode<VALUE> Node;
//          // This 'typedef' is an alias to the type of the linked list node.
//
//    private:
//      // TYPES
//      typedef bslstl::BidirectionalNodePool<VALUE, ALLOCATOR> Pool;
//          // This 'typedef' is an alias to the type of the memory pool.
//
//      typedef bslalg::BidirectionalLinkListUtil               Util;
//          // This 'typedef' is an alias to the utility 'struct' providing
//          // functions for constructing and manipulating linked lists.
//
//      typedef bslalg::BidirectionalLink                       Link;
//          // This 'typedef' is an alias to the type of the linked list link.
//
//      // DATA
//      Node *d_head_p;  // pointer to the head of the linked list
//      Node *d_tail_p;  // pointer to the tail of the linked list
//      Pool  d_pool;    // memory pool used to allocate memory
//
//
//    public:
//      // CREATORS
//      MyList(const ALLOCATOR& allocator = ALLOCATOR());
//          // Create an empty linked list that allocate memory using the
//          // specified 'allocator'.
//
//      ~MyList();
//          // Destroy this linked list by calling destructor for each element
//          // and deallocate all allocated storage.
//
//      // MANIPULATORS
//      void pushFront(const VALUE& value);
//          // Insert the specified 'value' at the front of this linked list.
//
//      void pushBack(const VALUE& value);
//          // Insert the specified 'value' at the end of this linked list.
//
//      //...
//  };
//..
// Now, we define the methods of 'MyMatrix':
//..
// CREATORS
//  template <class VALUE, class ALLOCATOR>
//  MyList<VALUE, ALLOCATOR>::MyList(const ALLOCATOR& allocator)
//  : d_head_p(0)
//  , d_tail_p(0)
//  , d_pool(allocator)
//  {
//  }
//
//  template <class VALUE, class ALLOCATOR>
//  MyList<VALUE, ALLOCATOR>::~MyList()
//  {
//      Link *link = d_head_p;
//      while (link) {
//          Link *next = link->nextLink();
//..
// Here, we call the memory pool's 'deleteNode' method to destroy the 'value'
// attribute of the node and return its memory footprint back to the pool:
//..
//          d_pool.deleteNode(static_cast<Node*>(link));
//          link = next;
//      }
//  }
//
// MANIPULATORS
//  template <class VALUE, class ALLOCATOR>
//  void
//  MyList<VALUE, ALLOCATOR>::pushFront(const VALUE& value)
//  {
//..
// Here, we call the memory pool's 'emplaceIntoNewNode' method to allocate a
// node and copy-construct the specified 'value' at the 'value' attribute of
// the node:
//..
//      Node *node = static_cast<Node *>(d_pool.emplaceIntoNewNode(value));
//..
// Note that the memory pool will allocate the footprint of the node using the
// allocator specified at construction.  If the (template parameter) type
// 'ALLOCATOR' is an instance of 'bsl::allocator' and the (template parameter)
// type 'VALUE' has the 'bslma::UsesBslmaAllocator' trait, then the allocator
// specified at construction will also be supplied to the copy-constructor of
// 'VALUE'.
//..
//      if (!d_head_p) {
//          d_tail_p = node;
//          node->setNextLink(0);
//          node->setPreviousLink(0);
//      }
//      else {
//          Util::insertLinkBeforeTarget(node, d_head_p);
//      }
//      d_head_p = node;
//  }
//
//  template <class VALUE, class ALLOCATOR>
//  void
//  MyList<VALUE, ALLOCATOR>::pushBack(const VALUE& value)
//  {
//..
// Here, just like how we implemented the 'pushFront' method, we call the
// pool's 'emplaceIntoNewNode' method to allocate a node and copy-construct the
// specified 'value' at the 'value' attribute of the node:
//..
//      Node *node = static_cast<Node *>(d_pool.emplaceIntoNewNode(value));
//      if (!d_head_p) {
//          d_head_p = node;
//          node->setNextLink(0);
//          node->setPreviousLink(0);
//      }
//      else {
//          Util::insertLinkAfterTarget(node, d_tail_p);
//      }
//      d_tail_p = node;
//  }
//..

#include <bslscm_version.h>

#include <bslstl_simplepool.h>

#include <bslalg_bidirectionallink.h>
#include <bslalg_bidirectionalnode.h>

#include <bslma_allocatortraits.h>
#include <bslma_deallocatorproctor.h>

#include <bslmf_isbitwisemoveable.h>
#include <bslmf_movableref.h>
#include <bslmf_util.h>    // 'forward(V)'

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_util.h>

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

#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
// Include version that can be compiled with C++03
// Generated on Thu Oct 21 10:11:37 2021
// Command line: sim_cpp11_features.pl bslstl_bidirectionalnodepool.h
# define COMPILING_BSLSTL_BIDIRECTIONALNODEPOOL_H
# include <bslstl_bidirectionalnodepool_cpp03.h>
# undef COMPILING_BSLSTL_BIDIRECTIONALNODEPOOL_H
#else

namespace BloombergLP {
namespace bslstl {

                       // ===========================
                       // class BidirectionalNodePool
                       // ===========================

template <class VALUE, class ALLOCATOR>
class BidirectionalNodePool {
    // This class provides methods for creating and destroying nodes using the
    // appropriate allocator-traits of the (template parameter) type
    // 'ALLOCATOR'.

    // PRIVATE TYPES
    typedef SimplePool<bslalg::BidirectionalNode<VALUE>, ALLOCATOR> Pool;
        // This 'typedef' is an alias for the memory pool allocator.

    typedef typename Pool::AllocatorTraits                     AllocatorTraits;
        // This 'typedef' is an alias for the allocator traits defined by
        // 'SimplePool'.

    typedef bslmf::MovableRefUtil                              MoveUtil;
        // This typedef is a convenient alias for the utility associated with
        // movable references.

    // DATA
    Pool d_pool;  // pool for allocating memory

  private:
    // NOT IMPLEMENTED
    BidirectionalNodePool& operator=(const BidirectionalNodePool&);
    BidirectionalNodePool(const BidirectionalNodePool&);

  public:
    // PUBLIC TYPE
    typedef typename Pool::AllocatorType AllocatorType;
        // Alias for the allocator type defined by 'SimplePool'.

    typedef typename AllocatorTraits::size_type size_type;
        // Alias for the 'size_type' of the allocator defined by 'SimplePool'.

  public:
    // CREATORS
    explicit BidirectionalNodePool(const ALLOCATOR& allocator);
        // Create a 'BidirectionalNodePool' object that will use the specified
        // 'allocator' to supply memory for allocated node objects.  If the
        // (template parameter) 'ALLOCATOR' is 'bsl::allocator', then
        // 'allocator' shall be convertible to 'bslma::Allocator *'.

    BidirectionalNodePool(bslmf::MovableRef<BidirectionalNodePool> original);
        // Create a bidirectional node-pool, adopting all outstanding memory
        // allocations associated with the specified 'original' node-pool, that
        // will use the allocator associated with 'original' to supply memory
        // for allocated node objects.  'original' is left in a valid but
        // unspecified state.

    //! ~BidirectionalNodePool() = default;
        // Destroy the memory pool maintained by this object, releasing all
        // memory used by the nodes of the type 'BidirectionalNode<VALUE>' in
        // the pool.  Any memory allocated for the nodes' 'value' attribute of
        // the (template parameter) type 'VALUE' will be leaked unless the
        // nodes are explicitly destroyed via the 'destroyNode' method.

    // MANIPULATORS
    void adopt(bslmf::MovableRef<BidirectionalNodePool> pool);
        // Adopt all outstanding memory allocations associated with the
        // specified node 'pool'.  The behavior is undefined unless this pool
        // uses the same allocator as that associated with 'pool'.  The
        // behavior is also undefined unless this pool is in the
        // default-constructed state.

    AllocatorType& allocator();
        // Return a reference providing modifiable access to the allocator
        // supplying memory for the memory pool maintained by this object.  The
        // behavior is undefined if the allocator used by this object is
        // changed with this method.  Note that this method provides modifiable
        // access to enable a client to call non-'const' methods on the
        // allocator.

    bslalg::BidirectionalLink *cloneNode(
                                    const bslalg::BidirectionalLink& original);
        // Allocate a node of the type 'BidirectionalNode<VALUE>', and
        // copy-construct an object of the (template parameter) type 'VALUE'
        // having the same value as the specified 'original' at the 'value'
        // attribute of the node.  Return the address of the node.  Note that
        // the 'next' and 'prev' attributes of the returned node will be
        // uninitialized.

    void deleteNode(bslalg::BidirectionalLink *linkNode);
        // Destroy the 'VALUE' attribute of the specified 'linkNode' and return
        // the memory footprint of 'linkNode' to this pool for potential reuse.
        // The behavior is undefined unless 'node' refers to a
        // 'bslalg::BidirectionalNode<VALUE>' that was allocated by this pool.

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
    template <class... Args>
    bslalg::BidirectionalLink *emplaceIntoNewNode(Args&&... arguments);
        // Allocate a node of the type 'BidirectionalNode<VALUE>', and
        // construct in-place an object of the (template parameter) type
        // 'VALUE' with the specified constructor 'arguments'.  Return the
        // address of the node.  Note that the 'next' and 'prev' attributes of
        // the returned node will be uninitialized.
#endif

    bslalg::BidirectionalLink *moveIntoNewNode(
                                          bslalg::BidirectionalLink *original);
        // Allocate a node of the type 'BidirectionalNode<VALUE>', and
        // move-construct an object of the (template parameter) type 'VALUE'
        // with the (explicitly moved) value indicated by the 'value' attribute
        // of the specified 'original' link.  Return the address of the node.
        // Note that the 'next' and 'prev' attributes of the returned node will
        // be uninitialized.  Also note that the 'value' attribute of
        // 'original' is left in a valid but unspecified state.

    void release();
        // Relinquish all memory currently allocated with the memory pool
        // maintained by this object.

    void reserveNodes(size_type numNodes);
        // Add to this pool sufficient memory to satisfy memory requests for at
        // least the specified 'numNodes' before the pool replenishes.  The
        // additional memory is added irrespective of the amount of free memory
        // when called.  The behavior is undefined unless '0 < numNodes'.

    void swapRetainAllocators(BidirectionalNodePool& other);
        // Efficiently exchange the nodes of this object with those of the
        // specified 'other' object.  This method provides the no-throw
        // exception-safety guarantee.  The behavior is undefined unless
        // 'allocator() == other.allocator()'.

    void swapExchangeAllocators(BidirectionalNodePool& other);
        // Efficiently exchange the nodes and the allocator of this object with
        // those of the specified 'other' object.  This method provides the
        // no-throw exception-safety guarantee.

    // ACCESSORS
    const AllocatorType& allocator() const;
        // Return a reference providing non-modifiable access to the allocator
        // supplying memory for the memory pool maintained by this object.
};

// FREE FUNCTIONS
template <class VALUE, class ALLOCATOR>
void swap(BidirectionalNodePool<VALUE, ALLOCATOR>& a,
          BidirectionalNodePool<VALUE, ALLOCATOR>& b);
    // Efficiently exchange the nodes of the specified 'a' object with those of
    // the specified 'b' object.  This method provides the no-throw
    // exception-safety guarantee.  The behavior is undefined unless
    // 'a.allocator() == b.allocator()'.

}  // close package namespace


// ============================================================================
//                                TYPE TRAITS
// ============================================================================

// Type traits for HashTable:
//: o A HashTable is bitwise moveable if the allocator is bitwise moveable.

namespace bslmf {

template <class VALUE, class ALLOCATOR>
struct IsBitwiseMoveable<bslstl::BidirectionalNodePool<VALUE, ALLOCATOR> >
: bsl::integral_constant<bool, bslmf::IsBitwiseMoveable<ALLOCATOR>::value>
{};

}  // close namespace bslmf

// ============================================================================
//                  TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

namespace bslstl {

// CREATORS
template <class VALUE, class ALLOCATOR>
inline
BidirectionalNodePool<VALUE, ALLOCATOR>::BidirectionalNodePool(
                                                    const ALLOCATOR& allocator)
: d_pool(allocator)
{
}

template <class VALUE, class ALLOCATOR>
inline
BidirectionalNodePool<VALUE, ALLOCATOR>::BidirectionalNodePool(
                             bslmf::MovableRef<BidirectionalNodePool> original)
: d_pool(MoveUtil::move(MoveUtil::access(original).d_pool))
{
}

// MANIPULATORS
template <class VALUE, class ALLOCATOR>
inline
void BidirectionalNodePool<VALUE, ALLOCATOR>::adopt(
                                 bslmf::MovableRef<BidirectionalNodePool> pool)
{
    BidirectionalNodePool& lvalue = pool;
    d_pool.adopt(MoveUtil::move(lvalue.d_pool));
}

template <class VALUE, class ALLOCATOR>
inline
typename
SimplePool<bslalg::BidirectionalNode<VALUE>, ALLOCATOR>::AllocatorType&
BidirectionalNodePool<VALUE, ALLOCATOR>::allocator()
{
    return d_pool.allocator();
}

template <class VALUE, class ALLOCATOR>
inline
bslalg::BidirectionalLink *
BidirectionalNodePool<VALUE, ALLOCATOR>::cloneNode(
                                     const bslalg::BidirectionalLink& original)
{
    return emplaceIntoNewNode(
       static_cast<const bslalg::BidirectionalNode<VALUE>&>(original).value());
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
template <class VALUE, class ALLOCATOR>
template <class... Args>
inline
bslalg::BidirectionalLink *
BidirectionalNodePool<VALUE, ALLOCATOR>::emplaceIntoNewNode(
                                                           Args&&... arguments)
{
    bslalg::BidirectionalNode<VALUE> *node = d_pool.allocate();
    bslma::DeallocatorProctor<Pool> proctor(node, &d_pool);

    AllocatorTraits::construct(
                             allocator(),
                             bsls::Util::addressOf(node->value()),
                             BSLS_COMPILERFEATURES_FORWARD(Args,arguments)...);
    proctor.release();
    return node;
}
#endif

template <class VALUE, class ALLOCATOR>
inline
bslalg::BidirectionalLink *
BidirectionalNodePool<VALUE, ALLOCATOR>::moveIntoNewNode(
                                           bslalg::BidirectionalLink *original)
{
    return emplaceIntoNewNode(MoveUtil::move(
        static_cast<bslalg::BidirectionalNode<VALUE> *>(original)->value()));
}

template <class VALUE, class ALLOCATOR>
void BidirectionalNodePool<VALUE, ALLOCATOR>::deleteNode(
                                           bslalg::BidirectionalLink *linkNode)
{
    BSLS_ASSERT(linkNode);

    bslalg::BidirectionalNode<VALUE> *node =
                     static_cast<bslalg::BidirectionalNode<VALUE> *>(linkNode);
    AllocatorTraits::destroy(allocator(),
                             bsls::Util::addressOf(node->value()));
    d_pool.deallocate(node);
}

template <class VALUE, class ALLOCATOR>
inline
void BidirectionalNodePool<VALUE, ALLOCATOR>::release()
{
    d_pool.release();
}

template <class VALUE, class ALLOCATOR>
inline
void BidirectionalNodePool<VALUE, ALLOCATOR>::reserveNodes(size_type numNodes)
{
    BSLS_ASSERT_SAFE(0 < numNodes);

    d_pool.reserve(numNodes);
}

template <class VALUE, class ALLOCATOR>
inline
void BidirectionalNodePool<VALUE, ALLOCATOR>::swapRetainAllocators(
                                BidirectionalNodePool<VALUE, ALLOCATOR>& other)
{
    BSLS_ASSERT_SAFE(allocator() == other.allocator());

    d_pool.quickSwapRetainAllocators(other.d_pool);
}

template <class VALUE, class ALLOCATOR>
inline
void BidirectionalNodePool<VALUE, ALLOCATOR>::swapExchangeAllocators(
                                BidirectionalNodePool<VALUE, ALLOCATOR>& other)
{
    d_pool.quickSwapExchangeAllocators(other.d_pool);
}

// ACCESSORS
template <class VALUE, class ALLOCATOR>
inline
const typename
              SimplePool<bslalg::BidirectionalNode<VALUE>, ALLOCATOR>::
                                                                 AllocatorType&
BidirectionalNodePool<VALUE, ALLOCATOR>::allocator() const
{
    return d_pool.allocator();
}

}  // close package namespace

template <class VALUE, class ALLOCATOR>
inline
void bslstl::swap(bslstl::BidirectionalNodePool<VALUE, ALLOCATOR>& a,
                  bslstl::BidirectionalNodePool<VALUE, ALLOCATOR>& b)
{
    a.swapRetainAllocators(b);
}

}  // close enterprise namespace

#endif // End C++11 code

#endif

// ----------------------------------------------------------------------------
// Copyright 2019 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 ----------------------------------