// bslma_allocatortraits.h                                            -*-C++-*-
#ifndef INCLUDED_BSLMA_ALLOCATORTRAITS
#define INCLUDED_BSLMA_ALLOCATORTRAITS

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

//@PURPOSE: Provide a uniform interface to standard allocator types.
//
//@CLASSES:
//  bsl::allocator_traits: Uniform interface to standard allocator types
//
//@SEE_ALSO: bslma_allocator, bslma_stdallocator
//
// TBD: update component-level doc
//@DESCRIPTION: The standard 'allocator_traits' class template is defined in
// the C++11 standard ([allocator.traits]) as a uniform mechanism for accessing
// nested types within, and operations on, any standard-conforming allocator.
// An 'allocator_traits' specialization is stateless, and all of its member
// functions are static.  In most cases, facilities of 'allocator_traits' are
// straight pass-throughs for the same facilities from the 'ALLOC' template
// parameter.  For example, 'allocator_traits<X>::pointer' is the same as
// 'X::pointer' and 'allocator_traits<X>::allocate(x, n)' is the same as
// 'x.allocate(n)'.  The advantage of using 'allocator_traits' instead of
// directly using the allocator is that the 'allocator_traits' interface can
// supply parts of the interface that are missing from 'ALLOC'.  In fact, the
// most important purpose of 'allocator_traits' is to provide implementations
// of C++11 allocator features that were absent in C++03, thus allowing a C++03
// allocator to work with C++11 containers.
//
// This component provides a full C++11 interface for 'allocator_traits', but
// constrains the set of allocator types on which it may be instantiated.
// Specifically, this implementation does not provide defaults for C++03 types
// and functions, and has hard-wired implementations of the new C++11 features.
// Thus, the 'allocator_traits' template cannot be instantiated on an allocator
// type that does not provide a full compliment of types and functions required
// by the C++03 standard, and it will ignore any special C++11 features
// specified in 'ALLOC'.  This limitation exists because Bloomberg does not
// need the full functionality of the C++11 model, but needs only to
// distinguish between C++03 allocators and allocators that implement the BSLMA
// allocator model (see {'bslma_stdallocator'}).  The full feature set of
// 'allocator_traits' would require a lot of resources for implementation and
// (especially) testing.  Moreover, a full implementation would require
// metaprogramming that is too advanced for the feature set of the compilers
// currently in use at Bloomberg.  This interface is useful, however, as a way
// to future-proof containers against the eventual implementation of the full
// feature set, and to take advantage of the Bloomberg-specific features
// described below.
//
// There are two important (new) C++11 features provided by the
// 'allocator_traits' interface: the 'construct' function having a
// variable-length argument list (limited to 5 constructor arguments on
// compilers that don't support variadic templates) and the
// allocator-propagation traits.  The implementations of these features within
// this component are tuned to Bloomberg's needs.  The 'construct' member
// function will automatically forward the allocator to the constructed object
// iff the 'ALLOC' parameter is convertible from 'bslma::Allocator*' and the
// object being constructed has the 'bslma::UsesBslmaAllocator' type trait, as
// per standard Bloomberg practice.  The
// 'select_on_container_copy_construction' static member will return a
// default-constructed allocator iff 'ALLOC' is convertible from
// 'bslma::Allocator *' because bslma allocators should not be copied when a
// container is copy-constructed; otherwise this function will return a copy of
// the allocator, as per C++03 container rules.  The other propagation traits
// all have a 'false' value, so allocators are not propagated on assignment or
// swap.
//
// Note that use of this component will differ from a strict following of the
// C++03 standard, as the 'construct' and 'destroy' methods of the
// parameterized allocator type will not be called.  Rather, the target object
// will always be constructed at the address specified by the user, by calling
// the constructor in-place.  Similarly, the destructor will always be called
// directly, rather than using a parameterized allocator's 'destroy' method.
// Otherwise, this implementation will fully support the C++03 model, including
// use of allocators returning "smart pointers" from 'allocate'.
//
///Usage
///-----
// In this section we show intended usage of this component.
//
///Example 1: A Container Class
///- - - - - - - - - - - - - -
// This example demonstrates the intended use of 'allocator_traits' to
// implement a standard-conforming container class.  First, we create a
// container class that holds a single object and which meets the requirements
// both of a standard container and of a Bloomberg container.  I.e., when
// instantiated with an allocator argument it uses the standard allocator
// model; otherwise it uses the 'bslma' model.  We provide an alias,
// 'AllocTraits', to the specific 'allocator_traits' instantiation to simplify
// the implementation of each method that must allocate memory, or create or
// destroy elements.
//..
//  #include <bslma_allocatortraits.h>
//
//  using namespace BloombergLP;
//
//  template <class TYPE, class ALLOC = bsl::allocator<TYPE> >
//  class MyContainer {
//      // This class provides a container that always holds exactly one
//      // element, dynamically allocated using the specified allocator.
//
//      typedef bsl::allocator_traits<ALLOC> AllocTraits;
//          // Alias for the 'allocator_traits' instantiation to use for all
//          // memory management requests.
//
//      // DATA
//      ALLOC  d_allocator;
//      TYPE  *d_value_p;
//
//    public:
//      typedef TYPE  value_type;
//      typedef ALLOC allocator_type;
//      // etc.
//
//      // CREATORS
//      explicit MyContainer(const ALLOC& a = ALLOC());
//      explicit MyContainer(const TYPE& v, const ALLOC& a = ALLOC());
//      MyContainer(const MyContainer& other);
//      MyContainer(const MyContainer& other, const ALLOC& a);
//      ~MyContainer();
//
//      // MANIPULATORS
//      ALLOC get_allocator() const { return d_allocator; }
//
//      // ACCESSORS
//      TYPE&       front()       { return *d_value_p; }
//      const TYPE& front() const { return *d_value_p; }
//
//      // etc.
//..
// Next we define the type traits for 'MyContainer' so that it is recognized as
// an STL *sequence* container:
//: o Defines STL iterators
//: o Is bitwise moveable if the allocator is bitwise moveable
//: o Uses 'bslma' allocators if the 'ALLOC' template parameter is convertible
//:   from 'bslma::Allocator*'.
//..
//      // TRAITS
//
//      // We would do the following if 'bslalg' was accessible.
//      // BSLMF_NESTED_TRAIT_DECLARATION(
//      //    MyContainer, bslalg::HasStlIterators);
//
//      BSLMF_NESTED_TRAIT_DECLARATION_IF(
//          MyContainer,
//          bslmf::IsBitwiseMoveable,
//          bslmf::IsBitwiseMoveable<ALLOC>::value);
//
//      BSLMF_NESTED_TRAIT_DECLARATION_IF(
//          MyContainer,
//          bslma::UsesBslmaAllocator,
//          (bsl::is_convertible<bslma::Allocator*, ALLOC>::value));
//  };
//..
// Then we implement the constructors, which allocate memory and construct a
// 'TYPE' object in the allocated memory.  Because the allocation and
// construction are done in two separate steps, we need to create a proctor
// that will deallocate the allocated memory in case the constructor throws an
// exception.  The proctor uses the uniform interface provided by
// 'allocator_traits' to access the 'pointer' and 'deallocate' members of
// 'ALLOC':
//..
//  template <class ALLOC>
//  class MyContainerProctor {
//      // This class implements a proctor to release memory allocated during
//      // the construction of a 'MyContainer' object if the constructor for
//      // the container's data element throws an exception.  Such a proctor
//      // should be 'release'd once the element is safely constructed.
//
//      typedef typename bsl::allocator_traits<ALLOC>::pointer pointer;
//      ALLOC   d_alloc;
//      pointer d_data_p;
//
//    public:
//      MyContainerProctor(const ALLOC& a, pointer p)
//          : d_alloc(a), d_data_p(p) { }
//
//      ~MyContainerProctor() {
//          if (d_data_p) {
//              bsl::allocator_traits<ALLOC>::deallocate(d_alloc, d_data_p, 1);
//          }
//      }
//
//      void release() { d_data_p = pointer(); }
//  };
//..
// Next, we perform the actual allocation and construction using the 'allocate'
// and 'construct' members of 'allocator_traits', which provide the correct
// semantic for passing the allocator to the constructed object when
// appropriate:
//..
//  template <class TYPE, class ALLOC>
//  MyContainer<TYPE, ALLOC>::MyContainer(const ALLOC& a)
//      : d_allocator(a)
//  {
//      d_value_p = AllocTraits::allocate(d_allocator, 1);
//      MyContainerProctor<ALLOC> proctor(a, d_value_p);
//      // Call 'construct' with no constructor arguments
//      AllocTraits::construct(d_allocator, d_value_p);
//      proctor.release();
//  }
//
//  template <class TYPE, class ALLOC>
//  MyContainer<TYPE, ALLOC>::MyContainer(const TYPE& v, const ALLOC& a)
//      : d_allocator(a)
//  {
//      d_value_p = AllocTraits::allocate(d_allocator, 1);
//      MyContainerProctor<ALLOC> proctor(a, d_value_p);
//      // Call 'construct' with one constructor argument of type 'TYPE'
//      AllocTraits::construct(d_allocator, d_value_p, v);
//      proctor.release();
//  }
//..
// Next, the copy constructor for 'MyContainer' needs to conditionally copy the
// allocator from the 'other' container.  The copy constructor uses
// 'allocator_traits::select_on_container_copy_construction' to decide whether
// to copy the 'other' allocator (for non-bslma allocators) or to
// default-construct the allocator (for bslma allocators).
//..
//  template <class TYPE, class ALLOC>
//  MyContainer<TYPE, ALLOC>::MyContainer(const MyContainer& other)
//      : d_allocator(bsl::allocator_traits<ALLOC>::
//                    select_on_container_copy_construction(other.d_allocator))
//  {
//      d_value_p = AllocTraits::allocate(d_allocator, 1);
//      MyContainerProctor<ALLOC> proctor(d_allocator, d_value_p);
//      AllocTraits::construct(d_allocator, d_value_p, *other.d_value_p);
//      proctor.release();
//  }
//..
// Now, the destructor uses 'allocator_traits' functions to destroy and
// deallocate the value object:
//..
//  template <class TYPE, class ALLOC>
//  MyContainer<TYPE, ALLOC>::~MyContainer()
//  {
//      AllocTraits::destroy(d_allocator, d_value_p);
//      AllocTraits::deallocate(d_allocator, d_value_p, 1);
//  }
//..
// Finally, we perform a simple test of 'MyContainer', instantiating it with
// element type 'int':
//..
//  int usageExample1()
//  {
//      bslma::TestAllocator testAlloc;
//      MyContainer<int> C1(123, &testAlloc);
//      assert(C1.get_allocator() == bsl::allocator<int>(&testAlloc));
//      assert(C1.front() == 123);
//
//      MyContainer<int> C2(C1);
//      assert(C2.get_allocator() == bsl::allocator<int>());
//      assert(C2.front() == 123);
//
//      return 0;
//  }
//..
///Example 2: C++03 Allocators
///- - - - - - - - - - - - - -
// This example shows that when 'MyContainer' is instantiated with a C++03
// allocator, that the allocator is a) copied on copy construction and b) is
// not propagated from the container to its elements.  Firstly we create a
// representative element class, 'MyType', that allocates memory using the
// bslma allocator protocol:
//..
//  #include <bslma_default.h>
//
//  class MyType {
//
//      bslma::Allocator *d_allocator_p;
//      // etc.
//    public:
//      // TRAITS
//      BSLMF_NESTED_TRAIT_DECLARATION(MyType, bslma::UsesBslmaAllocator);
//
//      // CREATORS
//      explicit MyType(bslma::Allocator* basicAlloc = 0)
//         : d_allocator_p(bslma::Default::allocator(basicAlloc)) { /* ... */ }
//      MyType(const MyType&)
//          : d_allocator_p(bslma::Default::allocator(0)) { /* ... */ }
//      MyType(const MyType&, bslma::Allocator* basicAlloc)
//         : d_allocator_p(bslma::Default::allocator(basicAlloc)) { /* ... */ }
//      // etc.
//
//      // ACCESSORS
//      bslma::Allocator *allocator() const { return d_allocator_p; }
//
//      // etc.
//  };
//..
// Then we create a C++03-style allocator class template:
//..
//  template <class TYPE>
//  class MyCpp03Allocator {
//      int d_state;
//
//    public:
//      typedef TYPE        value_type;
//      typedef TYPE       *pointer;
//      typedef const TYPE *const_pointer;
//      typedef unsigned    size_type;
//      typedef int         difference_type;
//
//      template <class OTHER>
//      struct rebind {
//          typedef MyCpp03Allocator<OTHER> other;
//      };
//
//      // CREATORS
//      explicit MyCpp03Allocator(int state = 0) : d_state(state) { }
//
//      // ALLOCATION FUNCTIONS
//      TYPE* allocate(size_type n, const void* = 0)
//          { return static_cast<TYPE *>(::operator new(sizeof(TYPE) * n)); }
//
//      void deallocate(TYPE* p, size_type) { ::operator delete(p); }
//
//      // ELEMENT CREATION FUNCTIONS
//      template <class ELEMENT_TYPE>
//      void construct(ELEMENT_TYPE *p)
//      {
//          ::new (static_cast<void *>(p)) ELEMENT_TYPE();
//      }
//      template <class ELEMENT_TYPE, class A1>
//      void construct(ELEMENT_TYPE *p,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A1) a1)
//      {
//          ::new (static_cast<void *>(p))
//              ELEMENT_TYPE(BSLS_COMPILERFEATURES_FORWARD(A1, a1));
//      }
//      template <class ELEMENT_TYPE, class A1, class A2>
//      void construct(ELEMENT_TYPE *p,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A1) a1,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A2) a2)
//      {
//          ::new (static_cast<void *>(p))
//              ELEMENT_TYPE(BSLS_COMPILERFEATURES_FORWARD(A1, a1),
//                           BSLS_COMPILERFEATURES_FORWARD(A2, a2));
//      }
//
//      template <class ELEMENT_TYPE, class A1, class A2, class A3>
//      void construct(ELEMENT_TYPE *p,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A1) a1,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A2) a2,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A3) a3)
//      {
//          ::new (static_cast<void *>(p))
//              ELEMENT_TYPE(BSLS_COMPILERFEATURES_FORWARD(A1, a1),
//                           BSLS_COMPILERFEATURES_FORWARD(A2, a2),
//                           BSLS_COMPILERFEATURES_FORWARD(A3, a3));
//      }
//
//      template <class ELEMENT_TYPE, class A1, class A2, class A3, class A4>
//      void construct(ELEMENT_TYPE *p,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A1) a1,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A2) a2,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A3) a3,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A4) a4)
//      {
//          ::new (static_cast<void *>(p))
//              ELEMENT_TYPE(BSLS_COMPILERFEATURES_FORWARD(A1, a1),
//                           BSLS_COMPILERFEATURES_FORWARD(A2, a2),
//                           BSLS_COMPILERFEATURES_FORWARD(A3, a3),
//                           BSLS_COMPILERFEATURES_FORWARD(A4, a4));
//      }
//
//      template <class ELEMENT_TYPE,
//                class A1,
//                class A2,
//                class A3,
//                class A4,
//                class A5>
//      void construct(ELEMENT_TYPE *p,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A1) a1,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A2) a2,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A3) a3,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A4) a4,
//                     BSLS_COMPILERFEATURES_FORWARD_REF(A5) a5)
//      {
//          ::new (static_cast<void *>(p))
//              ELEMENT_TYPE(BSLS_COMPILERFEATURES_FORWARD(A1, a1),
//                           BSLS_COMPILERFEATURES_FORWARD(A2, a2),
//                           BSLS_COMPILERFEATURES_FORWARD(A3, a3),
//                           BSLS_COMPILERFEATURES_FORWARD(A4, a4),
//                           BSLS_COMPILERFEATURES_FORWARD(A5, a5));
//      }
//
//      template <class ELEMENT_TYPE>
//      void destroy(ELEMENT_TYPE *p) { p->~ELEMENT_TYPE(); }
//
//      // ACCESSORS
//      static size_type max_size() { return UINT_MAX / sizeof(TYPE); }
//
//      int state() const { return d_state; }
//  };
//
//  template <class TYPE1, class TYPE2>
//  inline
//  bool operator==(const MyCpp03Allocator<TYPE1>& lhs,
//                  const MyCpp03Allocator<TYPE2>& rhs)
//  {
//      return lhs.state() == rhs.state();
//  }
//
//  template <class TYPE1, class TYPE2>
//  inline
//  bool operator!=(const MyCpp03Allocator<TYPE1>& lhs,
//                  const MyCpp03Allocator<TYPE2>& rhs)
//  {
//      return ! (lhs == rhs);
//  }
//..
// Finally we instantiate 'MyContainer' using this allocator type and verify
// that elements are constructed using the default allocator (because the
// allocator is not propagated from the container).  We also verify that the
// allocator is copied on copy-construction:
//..
//  int usageExample2()
//  {
//      typedef MyCpp03Allocator<MyType> MyTypeAlloc;
//
//      MyContainer<MyType, MyTypeAlloc> C1a(MyTypeAlloc(1));
//      assert((bsl::is_same<MyContainer<MyType, MyTypeAlloc>::allocator_type,
//                              MyTypeAlloc>::value));
//      assert(C1a.get_allocator() == MyTypeAlloc(1));
//      assert(C1a.front().allocator() == bslma::Default::defaultAllocator());
//
//      MyContainer<MyType, MyTypeAlloc> C2a(C1a);
//      assert(C2a.get_allocator() == C1a.get_allocator());
//      assert(C2a.get_allocator() != MyTypeAlloc());
//      assert(C2a.front().allocator() == bslma::Default::defaultAllocator());
//
//      MyType                           dummy;
//      MyContainer<MyType, MyTypeAlloc> C1b(dummy, MyTypeAlloc(1));
//      assert((bsl::is_same<MyContainer<MyType, MyTypeAlloc>::allocator_type,
//                              MyTypeAlloc>::value));
//      assert(C1b.get_allocator() == MyTypeAlloc(1));
//      assert(C1b.front().allocator() == bslma::Default::defaultAllocator());
//
//      MyContainer<MyType, MyTypeAlloc> C2b(C1b);
//      assert(C2b.get_allocator() == C1b.get_allocator());
//      assert(C2b.get_allocator() != MyTypeAlloc());
//      assert(C2b.front().allocator() == bslma::Default::defaultAllocator());
//
//      return 0;
//  }
//..

#include <bslscm_version.h>

#include <bslmf_enableif.h>
#include <bslmf_integralconstant.h>
#include <bslmf_isempty.h>
#include <bslmf_issame.h>
#include <bslmf_util.h>
#include <bslmf_voidtype.h>

#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_util.h>     // 'forward<T>(V)'

#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
// Include version that can be compiled with C++03
// Generated on Fri May 13 11:05:19 2022
// Command line: sim_cpp11_features.pl bslma_allocatortraits.h
# define COMPILING_BSLMA_ALLOCATORTRAITS_H
# include <bslma_allocatortraits_cpp03.h>
# undef COMPILING_BSLMA_ALLOCATORTRAITS_H
#else

#include <limits>

namespace BloombergLP {
namespace bslma {


                      // ================================
                      // AllocatorTraits_HasIsAlwaysEqual
                      // ================================

template <class ALLOC>
struct AllocatorTraits_HasIsAlwaysEqual {
    // This 'struct' template provides a mechanism for determining whether a
    // given (template parameter) 'ALLOCATOR_TYPE' defines a nested alias named
    //'is_always_equal'.  The static boolean member 'value' (nested alias
    // named 'type') is 'true' ('bsl::true_type') if 'ALLOCATOR_TYPE' defines
    // such an alias, and 'false' ('bsl::false_type') otherwise.

  private:
    // PRIVATE TYPES
    typedef struct { char d_a;    } yes_type;
    typedef struct { char d_a[2]; } no_type;

    // PRIVATE CLASS METHODS
    template <class U>
    static yes_type match(typename U::is_always_equal *);
    template <class U>
    static no_type match(...);
        // Return 'yes_type' if the (template parameter) 'TYPE' defines a
        // nested alias named 'is_always_equal', and 'no_type' otherwise.

  public:
    // PUBLIC CLASS DATA
    static const bool value = sizeof(match<ALLOC>(0)) == sizeof(yes_type);

    // PUBLIC TYPES
    typedef bsl::integral_constant<bool, value> type;
};

                       // =============================
                       // AllocatorTraits_IsAlwaysEqual
                       // =============================

template <class ALLOC, bool = AllocatorTraits_HasIsAlwaysEqual<ALLOC>::value>
struct AllocatorTraits_IsAlwaysEqual : public ALLOC::is_always_equal
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'is_always_equal' to the nested type alias in the given (template
    // parameter) 'ALLOC' if 'ALLOC' defines such an alias (i.e., if
    // 'true == AllocatorTraits_HasIsAlwaysEqual<ALLOCATOR_TYPE>::value').
};

template <class ALLOC>
struct AllocatorTraits_IsAlwaysEqual<ALLOC, false>
                                  : public bsl::is_empty<ALLOC>
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'is_always_equal' to 'bsl::is_empty<ALLOC>' if the given (template
    // parameter) 'ALLOC' does not define such an alias (i.e., if
    // 'false == AllocatorTraits_HasIsAlwaysEqual<ALLOCATOR_TYPE>::value').
};

                   // =====================================
                   // AllocatorTraits_HasSelectOnCopyMethod
                   // =====================================

template <class ALLOCATOR_TYPE>
struct AllocatorTraits_HasSelectOnCopyMethod {
    // This 'struct' template provides a mechanism for determining whether a
    // given (template parameter) 'ALLOCATOR_TYPE' defines a 'const' member
    // function named 'select_on_container_copy_construction' that takes no
    // arguments and returns an 'ALLOCATOR_TYPE' object by value.  The static
    // boolean 'value' (nested 'type' alias) is 'true' ('bsl::true_type') if
    // 'ALLOCATOR_TYPE' defines such a method, and 'false' ('bsl::false_type')
    // otherwise.

  private:
    typedef struct { char a;    } yes_type;
    typedef struct { char a[2]; } no_type;

    template <class T, T> struct MatchType { };
        // This 'struct' template provides a mechanism to check if a type
        // matches an instance within a SFINAE context.

    template <class T>
    struct MethodAlias { typedef T (T::*Method)() const; };

    template <class TYPE>
    static yes_type match(MatchType<typename MethodAlias<TYPE>::Method,
                          &TYPE::select_on_container_copy_construction> *);
    template <class TYPE>
    static no_type match(...);
        // Return 'yes_type' if the (template parameter) 'TYPE' defines a const
        // member function named 'select_on_container_copy_construction' taking
        // no arguments and returning a 'TYPE' object by value, and 'no_type'
        // otherwise.

  public:
    static const bool value =
                          sizeof(match<ALLOCATOR_TYPE>(0)) == sizeof(yes_type);
    typedef bsl::integral_constant<bool, value> type;
};

                    // ===================================
                    // AllocatorTraits_HasPropOnCopyAssign
                    // ===================================

template <class ALLOCATOR_TYPE>
struct AllocatorTraits_HasPropOnCopyAssign {
    // This 'struct' template provides a mechanism for determining whether a
    // given (template parameter) 'ALLOCATOR_TYPE' defines a nested alias named
    //'propagate_on_container_copy_assignment'.  The static boolean member
    // 'value' (nested alias named 'type') is 'true' ('bsl::true_type') if
    // 'ALLOCATOR_TYPE' defines such an alias, and 'false' ('bsl::false_type')
    // otherwise.

  private:
    typedef struct { char a;    } yes_type;
    typedef struct { char a[2]; } no_type;

    template <class U>
    static
    yes_type match(typename U::propagate_on_container_copy_assignment *);
    template <class U>
    static no_type match(...);
        // Return 'yes_type' if the (template parameter) 'TYPE' defines a
        // nested alias named 'propagate_on_container_copy_assignment', and
        // 'no_type' otherwise.

  public:
    static const bool value =
                          sizeof(match<ALLOCATOR_TYPE>(0)) == sizeof(yes_type);
    typedef bsl::integral_constant<bool, value> type;
};

                      // ================================
                      // AllocatorTraits_PropOnCopyAssign
                      // ================================

template <class ALLOCATOR_TYPE,
          bool = AllocatorTraits_HasPropOnCopyAssign<ALLOCATOR_TYPE>::value>
struct AllocatorTraits_PropOnCopyAssign : bsl::false_type
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'propagate_on_container_copy_assignment' to 'bsl::false_type' if the
    // given (template parameter) 'ALLOCATOR_TYPE' does not define such an
    // alias (i.e.,
    // 'false == AllocatorTraits_HasPropOnCopyAssign<ALLOCATOR_TYPE>::value').
};

template <class ALLOC>
struct AllocatorTraits_PropOnCopyAssign<ALLOC, true>
                       : public ALLOC::propagate_on_container_copy_assignment
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'propagate_on_container_copy_assignment' to the nested type alias in the
    // given (template parameter) 'ALLOCATOR_TYPE' if 'ALLOCATOR_TYPE' defines
    // such an alias (i.e.,
    // 'true == AllocatorTraits_HasPropOnCopyAssign<ALLOCATOR_TYPE>::value').
};

                    // ===================================
                    // AllocatorTraits_HasPropOnMoveAssign
                    // ===================================

template <class ALLOC>
struct AllocatorTraits_HasPropOnMoveAssign {
    // This 'struct' template provides a mechanism for determining whether a
    // given (template parameter) 'ALLOCATOR_TYPE' defines a nested alias named
    //'propagate_on_container_move_assignment'.  The static boolean member
    // 'value' (nested alias named 'type') is 'true' ('bsl::true_type') if
    // 'ALLOCATOR_TYPE' defines such an alias, and 'false' ('bsl::false_type')
    // otherwise.

  private:
    typedef struct { char a;    } yes_type;
    typedef struct { char a[2]; } no_type;

    template <class U>
    static
    yes_type match(typename U::propagate_on_container_move_assignment *);
    template <class U>
    static no_type match(...);
        // Return 'yes_type' if the (template parameter) 'TYPE' defines a
        // nested alias named 'propagate_on_container_move_assignment', and
        // 'no_type' otherwise.

  public:
    static const bool value = sizeof(match<ALLOC>(0)) == sizeof(yes_type);
    typedef bsl::integral_constant<bool, value> type;
};

                      // ================================
                      // AllocatorTraits_PropOnMoveAssign
                      // ================================

template <class ALLOC,
          bool = AllocatorTraits_HasPropOnMoveAssign<ALLOC>::value>
struct AllocatorTraits_PropOnMoveAssign : bsl::false_type
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'propagate_on_container_move_assignment' to 'bsl::false_type' if the
    // given (template parameter) 'ALLOCATOR_TYPE' does not define such an
    // alias (i.e.,
    // 'false == AllocatorTraits_HasPropOnMoveAssign<ALLOCATOR_TYPE>::value').
};

template <class ALLOC>
struct AllocatorTraits_PropOnMoveAssign<ALLOC, true>
                       : public ALLOC::propagate_on_container_move_assignment
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'propagate_on_container_move_assignment' to the nested type alias in the
    // given (template parameter) 'ALLOCATOR_TYPE' if 'ALLOCATOR_TYPE' defines
    // such an alias (i.e.,
    // 'true == AllocatorTraits_HasPropOnMoveAssign<ALLOCATOR_TYPE>::value').
};

                       // =============================
                       // AllocatorTraits_HasPropOnSwap
                       // =============================

template <class ALLOC>
struct AllocatorTraits_HasPropOnSwap {
    // This 'struct' template provides a mechanism for determining whether a
    // given (template parameter) 'ALLOCATOR_TYPE' defines a nested alias named
    //'propagate_on_container_swap'.  The static boolean member 'value' (nested
    // alias named 'type') is 'true' ('bsl::true_type') if 'ALLOCATOR_TYPE'
    // defines such an alias, and 'false' ('bsl::false_type') otherwise.

  private:
    typedef struct { char a;    } yes_type;
    typedef struct { char a[2]; } no_type;

    template <class U>
    static
    yes_type match(typename U::propagate_on_container_swap *);
    template <class U>
    static no_type match(...);
        // Return 'yes_type' if the (template parameter) 'TYPE' defines a
        // nested alias named 'propagate_on_container_swap', and 'no_type'
        // otherwise.

  public:
    static const bool value = sizeof(match<ALLOC>(0)) == sizeof(yes_type);
    typedef bsl::integral_constant<bool, value> type;
};

                         // ==========================
                         // AllocatorTraits_PropOnSwap
                         // ==========================

template <class ALLOC, bool = AllocatorTraits_HasPropOnSwap<ALLOC>::value>
struct AllocatorTraits_PropOnSwap : bsl::false_type
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'propagate_on_container_swap' to 'bsl::false_type' if the given
    // (template parameter) 'ALLOCATOR_TYPE' does not define such an alias
    // (i.e., 'false == AllocatorTraits_HasPropOnSwap<ALLOCATOR_TYPE>::value').
};

template <class ALLOC>
struct AllocatorTraits_PropOnSwap<ALLOC, true>
                                  : public ALLOC::propagate_on_container_swap
{
    // This 'struct' template sets the boolean type for the attribute named
    // 'propagate_on_container_swap' to the nested type alias in the given
    // (template parameter) 'ALLOCATOR_TYPE' if 'ALLOCATOR_TYPE' defines such
    // an alias (i.e.,
    // 'false == AllocatorTraits_HasPropOnSwap<ALLOCATOR_TYPE>::value').
};

#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE) &&                        \
    defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) &&               \
    defined(BSLS_COMPILERFEATURES_SUPPORT_VARIADIC_TEMPLATES)

                     // ==================================
                     // AllocatorTraits_HasConstructMethod
                     // ==================================

template <class T, class Return, class... Args>
struct AllocatorTraits_HasConstructMethod {
  private:
    template <class U>
    static auto match(U *) ->
        typename bsl::is_same<decltype(bslmf::Util::declval<U>().construct(
                                             bslmf::Util::declval<Args>()...)),
                              Return>::type;
    template <class>
    static bsl::false_type match(...);

  public:
    typedef decltype(match<T>(0)) type;
    static const bool value = type::value;
};

                      // ================================
                      // AllocatorTraits_HasDestroyMethod
                      // ================================

template <class T, class Return, class... Args>
struct AllocatorTraits_HasDestroyMethod {
  private:
    template <class U>
    static auto match(U *) ->
        typename bsl::is_same<decltype(bslmf::Util::declval<U>().destroy(
                                             bslmf::Util::declval<Args>()...)),
                              Return>::type;
    template <class>
    static bsl::false_type match(...);

  public:
    typedef decltype(match<T>(0)) type;
    static const bool value = type::value;
};

#endif

                        // ===========================
                        // AllocatorTraits_PointerType
                        // ===========================

template <class T, class = void>
struct AllocatorTraits_PointerType {
    typedef typename T::value_type *type;
};


template <class T>
struct AllocatorTraits_PointerType<T, BSLMF_VOIDTYPE(typename T::pointer)> {
    typedef typename T::pointer type;
};

                      // ================================
                      // AllocatorTraits_ConstPointerType
                      // ================================

template <class T, class = void>
struct AllocatorTraits_ConstPointerType {
    typedef const typename T::value_type *type;
        // should be pointer_traits::rebind of template above
};


template <class T>
struct AllocatorTraits_ConstPointerType<
                                   T,
                                   BSLMF_VOIDTYPE(typename T::const_pointer)> {
    typedef typename T::const_pointer type;
};


                      // ===============================
                      // AllocatorTraits_VoidPointerType
                      // ===============================

template <class T, class = void>
struct AllocatorTraits_VoidPointerType {
    typedef void *type;
        // should be pointer_traits::rebind of template above
};


template <class T>
struct AllocatorTraits_VoidPointerType<
                                   T,
                                   BSLMF_VOIDTYPE(typename T::void_pointer)> {
    typedef typename T::void_pointer type;
};

                    // ====================================
                    // AllocatorTraits_ConstVoidPointerType
                    // ====================================

template <class T, class = void>
struct AllocatorTraits_ConstVoidPointerType {
    typedef const void *type;
        // should be pointer_traits::rebind of template above
};


template <class T>
struct AllocatorTraits_ConstVoidPointerType<
                             T,
                             BSLMF_VOIDTYPE(typename T::const_void_pointer)> {
    typedef typename T::const_void_pointer type;
};

                          // ========================
                          // AllocatorTraits_SizeType
                          // ========================

template <class T, class = void>
struct AllocatorTraits_SizeType {
    typedef std::size_t type;
};


template <class T>
struct AllocatorTraits_SizeType<T, BSLMF_VOIDTYPE(typename T::size_type)> {
    typedef typename T::size_type type;
};

                       // ==============================
                       // AllocatorTraits_DifferenceType
                       // ==============================

template <class T, class = void>
struct AllocatorTraits_DifferenceType {
    // should be pointer_traits::rebind of template above
    typedef std::ptrdiff_t type;

};


template <class T>
struct AllocatorTraits_DifferenceType<
                             T,
                             BSLMF_VOIDTYPE(typename T::difference_type)> {
    typedef typename T::difference_type type;
};

                        // ===========================
                        // AllocatorTraits_RebindFront
                        // ===========================

#if defined(BSLS_COMPILERFEATURES_SUPPORT_VARIADIC_TEMPLATES)
template <class T, class U>
struct AllocatorTraits_RebindFront {
    // There shall be no member named 'type' unless T is a class template with
    // only type parameters.
};

template <template <class, class...> class ALLOC,
	  class T,
	  class ...ARGS,
	  class U>
struct AllocatorTraits_RebindFront<ALLOC<T, ARGS...>, U> {
    using type = ALLOC<U, ARGS...>;
};
#else
template <class T, class U>
struct AllocatorTraits_RebindFront {
    // There shall be no member named 'type' unless T is a class template with
    // only type parameters.
};

template <template <class> class ALLOC,
	  class T,
	  class U>
struct AllocatorTraits_RebindFront<ALLOC<T>, U> {
    typedef ALLOC<U> type;
};
#endif

                        // ===========================
                        // AllocatorTraits_RebindAlloc
                        // ===========================

template <class T, class U, class = void>
struct AllocatorTraits_RebindAlloc {
    // should be pointer_traits::rebind of template above
    typedef typename AllocatorTraits_RebindFront<T, U>::type type;

};

template <class T, class U>
struct AllocatorTraits_RebindAlloc<
                      T,
                      U,
                      BSLMF_VOIDTYPE(typename T::template rebind<U>::other)> {
    typedef typename T::template rebind<U>::other type;
};

                        // ===========================
                        // AllocatorTraits_CallMaxSize
                        // ===========================

#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE)
template <class T, class = void>
struct AllocatorTraits_CallMaxSize {

    // PUBLIC TYPES
    typedef typename AllocatorTraits_SizeType<T>::type SizeType;

    // PUBLIC CLASS METHODS
    static SizeType max_size(const T &)
        // Return the maximum size of the specified (template) parameter 'T'.
        // Also note that this method is defined inline to work around a
        // Windows compiler bug with SFINAE functions.
    {
        return std::numeric_limits<SizeType>::max() /
               sizeof(typename T::value_type);
    }
};

// Due to the dependence on expression SFINAE to detect the presence of a
// 'max_size' member of the allocator, this is only done on more modern
// platforms.
template <class T>
struct AllocatorTraits_CallMaxSize<
    T,
    BSLMF_VOIDTYPE(decltype(bslmf::Util::declval<T>().max_size()))> {

    // PUBLIC TYPES
    typedef typename AllocatorTraits_SizeType<T>::type SizeType;

    // PUBLIC CLASS METHODS
    static SizeType max_size(const T &alloc)
        // Return the maximum size of the specified 'alloc'.  Also note that
        // this method is defined inline to work around a Windows compiler bug
        // with SFINAE functions.
    {
        return alloc.max_size();
    }
};
#endif

} // close namespace bslma
} // close enterprise namespace

namespace bsl {

                           // ======================
                           // class allocator_traits
                           // ======================

template <class ALLOCATOR_TYPE>
struct allocator_traits {
    // This class supports the complete interface of the C++11
    // 'allocator_traits' class template, which provides a uniform mechanism
    // for accessing nested types within, and operations on, any
    // standard-conforming allocator.  A specialization of this class template
    // for 'bsl::allocator' provides support for Bloomberg's 'bslma' allocator
    // model (see the 'bslma_stdallocator' component for more details).  In
    // C++11 compilation environments, the 'construct' methods forward to the
    // allocator's 'construct' method if such a method matching the (variable
    // number of) specified constructor arguments exists; otherwise, the
    // 'construct' method falls back to invoking the constructor of the element
    // type directly.  In C++03 compilation environments, there is no reliable
    // way to detect if the type provide a method that matches a (variable
    // number of) specified arguments; therefore, we require that standard
    // allocator types define 'construct' methods taking a variable number of
    // arguments in those environments.  This implementation is not
    // fully-standard-conforming in that it does not support deduce data types
    // that are not specified in the allocator.

  private:

    typedef typename BloombergLP::bslma::AllocatorTraits_HasSelectOnCopyMethod<
                                    ALLOCATOR_TYPE>::type DelegateSelectMethod;

    static
    ALLOCATOR_TYPE selectOnCopyConstruct(const ALLOCATOR_TYPE& stdAllocator,
                                         true_type);
        // Return the result of invoking the
        // 'select_on_container_copy_construction' method on the specified
        // 'stdAllocator'.

    static
    ALLOCATOR_TYPE selectOnCopyConstruct(const ALLOCATOR_TYPE& stdAllocator,
                                         false_type);
        // Return the specified 'stdAllocator'.  Note that this behavior
        // enforces a default policy of propagating the allocator on copy
        // construction when using a standard allocator.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE) &&                        \
    defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) &&               \
    defined(BSLS_COMPILERFEATURES_SUPPORT_VARIADIC_TEMPLATES)
    template <class ELEMENT_TYPE, class... Args>
    static typename bsl::enable_if<
        BloombergLP::bslma::AllocatorTraits_HasConstructMethod<ALLOCATOR_TYPE,
                                                               void,
                                                               ELEMENT_TYPE *,
                                                               Args...>::value,
        void>::type
    privateConstruct(ALLOCATOR_TYPE&  basicAllocator,
                     ELEMENT_TYPE    *elementAddr,
                     Args&&...        arguments);
    template <class ELEMENT_TYPE, class... Args>
    static typename bsl::enable_if<
        !BloombergLP::bslma::AllocatorTraits_HasConstructMethod<
            ALLOCATOR_TYPE,
            void,
            ELEMENT_TYPE *,
            Args...>::value,
        void>::type
    privateConstruct(ALLOCATOR_TYPE&  basicAllocator,
                     ELEMENT_TYPE    *elementAddr,
                     Args&&...        arguments);
        // Construct an object of (template parameter) type 'ELEMENT_TYPE' at
        // the specified 'elementAddr', either by 1) calling the 'construct'
        // method on 'basicAllocator' with 'elemAddr' and the specified
        // (variable number of) 'arguments' if the (template parameter) type
        // 'ALLOCATOR_TYPE' defines such a method, or 2) forwarding the
        // specified (variable number of) 'arguments' to the constructor of
        // 'ELEMENT_TYPE' directly (and ignoring 'basicAllocator') otherwise.
        // The behavior is undefined unless 'elementAddr' refers to valid,
        // uninitialized storage.

    template <class ELEMENT_TYPE>
    static typename bsl::enable_if<
        BloombergLP::bslma::AllocatorTraits_HasDestroyMethod<
            ALLOCATOR_TYPE,
            void,
            ELEMENT_TYPE *>::value,
        void>::type
    privateDestroy(ALLOCATOR_TYPE& basicAllocator, ELEMENT_TYPE *elementAddr);

    template <class ELEMENT_TYPE>
    static typename bsl::enable_if<
        !BloombergLP::bslma::AllocatorTraits_HasDestroyMethod<
            ALLOCATOR_TYPE,
            void,
            ELEMENT_TYPE *>::value,
        void>::type
    privateDestroy(ALLOCATOR_TYPE& basicAllocator, ELEMENT_TYPE *elementAddr);
        // Destroy the object of (template parameter) type 'ELEMENT_TYPE' at
        // the specified 'elementAddr', either by 1) calling the 'destroy'
        // method on 'basicAllocator' with 'elemAddr' as the sole argument if
        // the (template parameter) type 'ALLOCATOR_TYPE' defines such a
        // method, or 2) calling the destructor directly on 'elementAddr' (and
        // ignoring 'basicAllocator') otherwise.  The behavior is undefined
        // unless 'elementAddr' refers to a valid, constructed object.
#endif

  public:
    // PUBLIC TYPES
    typedef ALLOCATOR_TYPE                            allocator_type;
    typedef typename ALLOCATOR_TYPE::value_type       value_type;

    typedef typename
         BloombergLP::bslma::AllocatorTraits_PointerType<ALLOCATOR_TYPE>::type
	                                              pointer;
    typedef typename
    BloombergLP::bslma::AllocatorTraits_ConstPointerType<ALLOCATOR_TYPE>::type
	                                              const_pointer;
    typedef typename
     BloombergLP::bslma::AllocatorTraits_VoidPointerType<ALLOCATOR_TYPE>::type
	                                              void_pointer;
    typedef typename BloombergLP::bslma::
                    AllocatorTraits_ConstVoidPointerType<ALLOCATOR_TYPE>::type
	                                              const_void_pointer;

    typedef typename
      BloombergLP::bslma::AllocatorTraits_DifferenceType<ALLOCATOR_TYPE>::type
	                                              difference_type;
    typedef typename
	    BloombergLP::bslma::AllocatorTraits_SizeType<ALLOCATOR_TYPE>::type
	                                              size_type;

#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
    template <class ELEMENT_TYPE>
    using rebind_alloc = typename
           BloombergLP::bslma::AllocatorTraits_RebindAlloc<ALLOCATOR_TYPE,
                                                           ELEMENT_TYPE>::type;

    template <class ELEMENT_TYPE>
    using rebind_traits = allocator_traits<rebind_alloc<ELEMENT_TYPE>>;
#else // !BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
    template <class ELEMENT_TYPE>
    struct rebind_alloc
        : BloombergLP::bslma::AllocatorTraits_RebindAlloc<ALLOCATOR_TYPE,
                                                          ELEMENT_TYPE>::type
    {
        // Note that this class attempts to emulate an alias template, but is
        // not complete.  In general, code that must support C++03 should use
        // 'rebind_traits<ELEMENT_TYPE>::allocator_type' instead of
        // 'rebind_alloc<ELEMENT_TYPE>' because that nested typedef is the
        // preferred actual allocator type and not a subclass of the desired
        // type.

        typedef typename BloombergLP::bslma::
                AllocatorTraits_RebindAlloc<ALLOCATOR_TYPE, ELEMENT_TYPE>::type
	                                                        allocator_type;

        template <typename ARG>
        rebind_alloc(const ARG& allocatorArg)
            // Convert from anything that can be used to cosntruct the base
            // type.  This might be better if SFINAE-ed out using
            // 'is_convertible', but stressing older compilers more seems
            // unwise.
        : allocator_type(allocatorArg)
        {
        }
    };

    template <class ELEMENT_TYPE>
    struct rebind_traits : allocator_traits<typename allocator_traits::template
                                    rebind_alloc<ELEMENT_TYPE>::allocator_type>
    {
    };
#endif // !BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES

    // Allocation functions

    static pointer allocate(ALLOCATOR_TYPE& basicAllocator, size_type n);
        // Return 'basicAllocator.allocate(n)'.

    static pointer allocate(ALLOCATOR_TYPE&    basicAllocator,
                            size_type          n,
                            const_void_pointer hint);
        // Return 'basicAllocator.allocate(n, hint)'.

    static void deallocate(ALLOCATOR_TYPE& basicAllocator,
                           pointer         elementAddr,
                           size_type       n);
        // Invoke 'basicAllocator.deallocate(elementAddr, n)'.  The behavior is
        // undefined unless the specified 'elementAddr' was returned from a
        // prior call to the 'allocate' method of an allocator that compares
        // equal to the specified 'allocator', and has not yet been passed to a
        // 'deallocate' call of such an allocator object.

    // Element creation functions

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=14
    template <class ELEMENT_TYPE, class... Args>
    static void construct(ALLOCATOR_TYPE&  basicAllocator,
                          ELEMENT_TYPE    *elementAddr,
                          Args&&...        arguments);
        // Construct an object of (template parameter) type 'ELEMENT_TYPE' at
        // the specified 'elementAddr', either by 1) calling the 'construct'
        // method on 'basicAllocator' with 'elemAddr' and the specified
        // (variable number of) 'arguments' if the (template parameter) type
        // 'ALLOCATOR_TYPE' defines such a method, or 2) forwarding the
        // specified (variable number of) 'arguments' to the constructor of
        // 'ELEMENT_TYPE' directly (and ignoring 'basicAllocator') otherwise.
        // The behavior is undefined unless 'elementAddr' refers to valid,
        // uninitialized storage.
#endif

    template <class ELEMENT_TYPE>
    static void destroy(ALLOCATOR_TYPE&  basicAllocator,
                        ELEMENT_TYPE    *elementAddr);
        // Destroy the object of (template parameter) type 'ELEMENT_TYPE' at
        // the specified 'elementAddr', either by 1) calling the 'destroy'
        // method on 'basicAllocator' with 'elemAddr' as the sole argument if
        // the (template parameter) type 'ALLOCATOR_TYPE' defines such a
        // method, or 2) calling the destructor directly on 'elementAddr' (and
        // ignoring 'basicAllocator') otherwise.  The behavior is undefined
        // unless 'elementAddr' refers to a valid, constructed object.

    static size_type max_size(const ALLOCATOR_TYPE& basicAllocator)
                                                         BSLS_KEYWORD_NOEXCEPT;
        // Return the largest number of 'value_type' objects that could
        // reasonably be returned by a single invocation of 'allocate' for the
        // specified 'allocator', i.e., 'allocator.max_size()'.

    // Allocator propagation traits
    static ALLOCATOR_TYPE
    select_on_container_copy_construction(const ALLOCATOR_TYPE& rhs);
        // Return a copy of the allocator that should be used to copy-
        // construct one container from another container whose allocator is
        // the specified 'rhs'.  If the parameterized 'ALLOCATOR_TYPE' defines
        // a method 'select_on_container_copy_construction', this function
        // returns the result of calling that method on 'rhs'; otherwise, this
        // method enforces the default policy of propagating the allocator on
        // copy construction, as is standard practice for standard allocators
        // (i.e., returns 'rhs').  Note that the specialization of this class
        // template for 'bsl::allocator' (in the 'bslma_stdallocator'
        // component) provides the alternate default behavior of *not*
        // propagating the allocator on copy construction (i.e., returning a
        // default-constructed allocator object).

    typedef typename BloombergLP::bslma::AllocatorTraits_IsAlwaysEqual<
                             ALLOCATOR_TYPE>::type is_always_equal;
        // Identical to, or derived from 'true_type' if two allocators of
        // parameterized 'ALLOCATOR_TYPE' always compare equal; otherwise
        // identical to or derived from 'false_type'.  This type is
        // 'ALLOCATOR_TYPE::is_always_equal' if such a type is defined, and
        // 'is_empty<ALLOCATOR_TYPE>' otherwise.

    typedef typename BloombergLP::bslma::AllocatorTraits_PropOnCopyAssign<
                  ALLOCATOR_TYPE>::type propagate_on_container_copy_assignment;
        // Identical to, or derived from 'true_type' if an allocator of
        // parameterized 'ALLOCATOR_TYPE' should be copied when a container
        // using that 'ALLOCATOR_TYPE' is copy-assigned; otherwise identical to
        // or derived from 'false_type'.  This type is
        // 'ALLOCATOR_TYPE::propagate_on_container_copy_assignment' if such a
        // type is defined, and 'false_type' otherwise.

    typedef typename BloombergLP::bslma::AllocatorTraits_PropOnMoveAssign<
                  ALLOCATOR_TYPE>::type propagate_on_container_move_assignment;
        // Identical to, or derived from 'true_type' if an allocator of
        // parameterized 'ALLOCATOR_TYPE' should be moved when a container
        // using that 'ALLOCATOR_TYPE' is move-assigned; otherwise identical to
        // or derived from 'false_type'.  This type is
        // 'ALLOCATOR_TYPE::propagate_on_container_move_assignment' if such a
        // type is defined, and 'false_type' otherwise.

    typedef typename BloombergLP::bslma::AllocatorTraits_PropOnSwap<
                             ALLOCATOR_TYPE>::type propagate_on_container_swap;
        // Identical to, or derived from 'true_type' if the allocators of
        // parameterized 'ALLOCATOR_TYPE' should be swapped when containers
        // using that 'ALLOCATOR_TYPE' are swapped; otherwise identical to or
        // derived from 'false_type'.  This type is
        // 'ALLOCATOR_TYPE::propagate_on_container_swap' if such a type is
        // defined, and 'false_type' otherwise.
};

                  // ========================================
                  // class allocator_traits<ALLOCATOR_TYPE *>
                  // ========================================

template <class ALLOCATOR_TYPE>
struct allocator_traits<ALLOCATOR_TYPE *> {
    // TBD: improve comment This is an empty class specialization of
    // 'allocator_traits' for pointer types that (intentionally) does not
    // define any of the traits typedefs.  It's needed in order make
    // unambiguous function overloads that take both a standard allocator by
    // value and a 'bslma::Allocator *'.  By using the typedefs defined in
    // 'allocator_traits' in the signature of functions taking standard
    // allocators, we can ensure that those overloads are not considered when
    // using 'bslma'-style allocators.
};

}  // close namespace bsl

// ============================================================================
//          INLINE AND TEMPLATE STATIC MEMBER FUNCTION DEFINITIONS
// ============================================================================


namespace bsl {

                           // ----------------------
                           // class allocator_traits
                           // ----------------------


template <class ALLOCATOR_TYPE>
inline
ALLOCATOR_TYPE allocator_traits<ALLOCATOR_TYPE>::selectOnCopyConstruct(
                                            const ALLOCATOR_TYPE& stdAllocator,
                                            true_type)
{
    return stdAllocator.select_on_container_copy_construction();
}

template <class ALLOCATOR_TYPE>
inline
ALLOCATOR_TYPE allocator_traits<ALLOCATOR_TYPE>::selectOnCopyConstruct(
                                            const ALLOCATOR_TYPE& stdAllocator,
                                            false_type)
{
    return stdAllocator;
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE) &&                        \
    defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) &&               \
    defined(BSLS_COMPILERFEATURES_SUPPORT_VARIADIC_TEMPLATES)
template <class ALLOCATOR_TYPE>
template <class ELEMENT_TYPE, class... Args>
inline
typename bsl::enable_if<
    BloombergLP::bslma::AllocatorTraits_HasConstructMethod<ALLOCATOR_TYPE,
                                                           void,
                                                           ELEMENT_TYPE *,
                                                           Args...>::value,
    void>::type
allocator_traits<ALLOCATOR_TYPE>::privateConstruct(
                                               ALLOCATOR_TYPE&  basicAllocator,
                                               ELEMENT_TYPE    *elementAddr,
                                               Args&&...        arguments)
{
    basicAllocator.construct(
        elementAddr, BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...);
}

template <class ALLOCATOR_TYPE>
template <class ELEMENT_TYPE, class... Args>
inline
typename bsl::enable_if<
    !BloombergLP::bslma::AllocatorTraits_HasConstructMethod<ALLOCATOR_TYPE,
                                                            void,
                                                            ELEMENT_TYPE *,
                                                            Args...>::value,
    void>::type
allocator_traits<ALLOCATOR_TYPE>::privateConstruct(ALLOCATOR_TYPE&,
                                                   ELEMENT_TYPE *elementAddr,
                                                   Args&&...     arguments)
{
    ::new (static_cast<void *>(elementAddr))
        ELEMENT_TYPE(BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...);
}

template <class ALLOCATOR_TYPE>
template <class ELEMENT_TYPE>
inline
typename bsl::enable_if<BloombergLP::bslma::AllocatorTraits_HasDestroyMethod<
                            ALLOCATOR_TYPE,
                            void,
                            ELEMENT_TYPE *>::value,
                        void>::type
allocator_traits<ALLOCATOR_TYPE>::privateDestroy(
                                               ALLOCATOR_TYPE&  basicAllocator,
                                               ELEMENT_TYPE    *elementAddr)
{
    basicAllocator.destroy(elementAddr);
}

template <class ALLOCATOR_TYPE>
template <class ELEMENT_TYPE>
inline
typename bsl::enable_if<!BloombergLP::bslma::AllocatorTraits_HasDestroyMethod<
                            ALLOCATOR_TYPE,
                            void,
                            ELEMENT_TYPE *>::value,
                        void>::type
allocator_traits<ALLOCATOR_TYPE>::privateDestroy(ALLOCATOR_TYPE&,
                                                 ELEMENT_TYPE *elementAddr)
{
    elementAddr->~ELEMENT_TYPE();
}
#endif

// Allocation functions

template <class ALLOCATOR_TYPE>
inline
typename allocator_traits<ALLOCATOR_TYPE>::pointer
allocator_traits<ALLOCATOR_TYPE>::allocate(ALLOCATOR_TYPE& basicAllocator,
                                           size_type n)
{
    return basicAllocator.allocate(n);
}

template <class ALLOCATOR_TYPE>
inline
typename allocator_traits<ALLOCATOR_TYPE>::pointer
allocator_traits<ALLOCATOR_TYPE>::allocate(ALLOCATOR_TYPE&    basicAllocator,
                                           size_type          n,
                                           const_void_pointer hint)
{
    return basicAllocator.allocate(n, hint);
}

template <class ALLOCATOR_TYPE>
inline
void
allocator_traits<ALLOCATOR_TYPE>::deallocate(ALLOCATOR_TYPE& basicAllocator,
                                             pointer         elementAddr,
                                             size_type       n)
{
    basicAllocator.deallocate(elementAddr, n);
}

// ELEMENT CREATION FUNCTIONS

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
template <class ALLOCATOR_TYPE>
template <class ELEMENT_TYPE, class... Args>
inline
void
allocator_traits<ALLOCATOR_TYPE>::construct(ALLOCATOR_TYPE&  basicAllocator,
                                            ELEMENT_TYPE    *elementAddr,
                                            Args&&...        arguments)
{
#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE)
    privateConstruct(basicAllocator,
                     elementAddr,
                     BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...);
#else
    // Cannot sniff out whether 'basicAllocator.construct(...)' is valid in
    // C++03, but allocators are required to have a 'construct' method, so just
    // call it.
    basicAllocator.construct(
        elementAddr, BSLS_COMPILERFEATURES_FORWARD(Args, arguments)...);
#endif
}
#endif

template <class ALLOCATOR_TYPE>
template <class ELEMENT_TYPE>
inline
void
allocator_traits<ALLOCATOR_TYPE>::destroy(ALLOCATOR_TYPE& stdAllocator,
                                          ELEMENT_TYPE    *elementAddr)
{
//  For full C++11 compatibility, this should check for the well-formedness of
//  the allocator-specific code that is commented out below (via some SFINAE
//  trickery), and switch to the 'DestructionUtil' implementation only if the
// 'destroy' member function is not available.

//    allocator.destroy(elementAddr);
#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE) &&                        \
    defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES)
    privateDestroy(stdAllocator, elementAddr);
#else
    elementAddr->~ELEMENT_TYPE();
    (void) stdAllocator;
#endif
}

template <class ALLOCATOR_TYPE>
inline
typename allocator_traits<ALLOCATOR_TYPE>::size_type
allocator_traits<ALLOCATOR_TYPE>::max_size(
                    const ALLOCATOR_TYPE& basicAllocator) BSLS_KEYWORD_NOEXCEPT
{
#if defined(BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE)
    return BloombergLP::bslma::
	 AllocatorTraits_CallMaxSize<ALLOCATOR_TYPE>::max_size(basicAllocator);
#else
    // Cannot sniff out whether 'basicAllocator.max_size()' is valid in C++03,
    // but for now require that allocators have a 'max_size' method and just
    // call it.
    return basicAllocator.max_size();
#endif
}

template <class ALLOCATOR_TYPE>
inline
ALLOCATOR_TYPE
allocator_traits<ALLOCATOR_TYPE>::select_on_container_copy_construction(
                                                     const ALLOCATOR_TYPE& rhs)
{
    return selectOnCopyConstruct(rhs, DelegateSelectMethod());
}

}  // close namespace bsl

#endif // End C++11 code

#endif // ! defined(INCLUDED_BSLMA_ALLOCATORTRAITS)

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