// bslma_constructionutil.h                                           -*-C++-*-
#ifndef INCLUDED_BSLMA_CONSTRUCTIONUTIL
#define INCLUDED_BSLMA_CONSTRUCTIONUTIL

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

//@PURPOSE: Provide methods to construct arbitrarily-typed objects uniformly.
//
//@CLASSES:
//  bslma::ConstructionUtil: namespace for methods to construct objects
//
//@SEE_ALSO: bslma_allocatortraits, bslma_destructionutil
//
//@DESCRIPTION: This component provides a 'struct', 'bslma::ConstructionUtil',
// that serves as a namespace for utility functions to construct objects of an
// arbitrary (template parameter) type, given an arbitrary number of arguments.
// These functions are useful in implementing 'allocator_trait' classes that,
// in turn, are used in implementing generic components such as containers.
// How a type is constructed may depend on several type traits.  The traits
// under consideration by this component are:
//..
//  Trait                                         Description
//  --------------------------------------------  -----------------------------
//  bsl::is_trivially_default_constructible       "TYPE has the trivial default
//                                                constructor trait", or
//                                                "TYPE has a trivial default
//                                                constructor"
//
//  bslma::UsesBslmaAllocator                     "the 'TYPE' constructor takes
//                                                an allocator argument", or
//                                                "'TYPE' supports 'bslma'-
//                                                style allocators"
//
//  bslmf::UsesAllocatorArgT                      "the 'TYPE' constructor takes
//                                                an allocator argument", and
//                                                optionally passes allocators
//                                                as the first two arguments to
//                                                each constructor, where the
//                                                tag type 'allocator_arg_t' is
//                                                first, and the allocator type
//                                                is second
//
//  bsl::is_trivially_copyable                    "TYPE has the bitwise
//                                                copyable trait", or
//                                                "TYPE is bitwise copyable"
//                                                (implies that it has a
//                                                trivial destructor too)
//
//  bslmf::IsBitwiseMoveable                      "TYPE has the bitwise
//                                                movable trait", or
//                                                "TYPE is bitwise movable"
//..
// This component provides full support for in-place construction of objects
// such that the object type's allocator policy is respected and all arguments
// are perfectly forwarded to the appropriate constructor.  This component also
// provides partial support for the C++20 'std::make_obj_using_allocator'
// utility via the (overloaded) 'bslma::ConstructionUtil::make' method.
// Currently, 'make' supports only default construction and construction from
// one (non-allocator) argument.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Using 'bslma::ConstructionUtil' to Implement a Container
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This example demonstrates the intended use of 'bslma::ConstructionUtil' to
// implement a simple container class that uses the 'bslma::Allocator' protocol
// for memory management.
//
// First, because allocation and construction are done in two separate steps,
// we need to define a proctor type that will deallocate the allocated memory
// in case the constructor throws an exception:
//..
//  template <class TYPE>
//  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.
//
//      // DATA
//      bslma::Allocator *d_allocator_p;
//      TYPE             *d_address_p;    // proctored memory
//
//    private:
//      // NOT IMPLEMENTED
//      MyContainerProctor(const MyContainerProctor&);             // = delete
//      MyContainerProctor& operator=(const MyContainerProctor&);  // = delete
//
//    public:
//      // CREATORS
//      MyContainerProctor(bslma::Allocator *allocator, TYPE *address)
//          // Create a proctor that conditionally manages the memory at the
//          // specified 'address', and that uses the specified 'allocator' to
//          // deallocate the block of memory (if not released -- see
//          // 'release') upon destruction.  The behavior is undefined unless
//          // 'allocator' is non-zero and supplied the memory at 'address'.
//      : d_allocator_p(allocator)
//      , d_address_p(address)
//      {
//      }
//
//      ~MyContainerProctor()
//          // Destroy this proctor, and deallocate the block of memory it
//          // manages (if any) by invoking the 'deallocate' method of the
//          // allocator that was supplied at construction of this proctor.  If
//          // no memory is currently being managed, this method has no effect.
//      {
//          if (d_address_p) {
//              d_allocator_p->deallocate(d_address_p);
//          }
//      }
//
//      // MANIPULATORS
//      void release()
//          // Release from management the block of memory currently managed by
//          // this proctor.  If no memory is currently being managed, this
//          // method has no effect.
//      {
//          d_address_p = 0;
//      }
//  };
//..
// Then, we create a container class that holds a single element and uses
// 'bslma' allocators:
//..
//  #include <bslma_constructionutil.h>
//
//  template <class TYPE>
//  class MyContainer {
//      // This class provides a container that always holds exactly one
//      // element, dynamically allocated using the specified 'bslma'
//      // allocator.
//
//      // DATA
//      TYPE             *d_value_p;
//      bslma::Allocator *d_allocator_p;
//
//    public:
//      // TRAITS
//      BSLMF_NESTED_TRAIT_DECLARATION(MyContainer, bslma::UsesBslmaAllocator);
//
//      // CREATORS
//      explicit MyContainer(bslma::Allocator *basicAllocator = 0);
//          // Create a container with a default-constructed element.
//          // Optionally specify a 'basicAllocator' used to supply memory.  If
//          // 'basicAllocator' is 0, the currently installed default allocator
//          // is used.
//
//      template <class OTHER>
//      explicit MyContainer(
//          BSLS_COMPILERFEATURES_FORWARD_REF(OTHER) value,
//          typename bsl::enable_if<bsl::is_convertible<OTHER, TYPE>::value,
//                                  void *>::type * = 0)
//          // Create a container with an element constructed by (perfectly)
//          // forwarding the specified 'value' and that uses the currently
//          // installed default allocator to supply memory.  Note that this
//          // constructor participates in overload resolution only if 'OTHER'
//          // is implicitly convertible to 'TYPE'.
//      : d_allocator_p(bslma::Default::defaultAllocator())
//      {
//          d_value_p =
//              static_cast<TYPE *>(d_allocator_p->allocate(sizeof(TYPE)));
//
//          MyContainerProctor<TYPE> proctor(d_allocator_p, d_value_p);
//
//          // Call 'construct' by forwarding 'value'.
//
//          bslma::ConstructionUtil::construct(
//              d_value_p,
//              d_allocator_p,
//              BSLS_COMPILERFEATURES_FORWARD(OTHER, value));
//          proctor.release();
//      }
//
//      template <class OTHER>
//      explicit MyContainer(
//          BSLS_COMPILERFEATURES_FORWARD_REF(OTHER)  value,
//          bslma::Allocator                         *basicAllocator);
//          // Create a container with an element constructed by (perfectly)
//          // forwarding the specified 'value' and that uses the specified
//          // 'basicAllocator' to supply memory.  If 'basicAllocator' is 0,
//          // the currently installed default allocator is used.  Note that
//          // this constructor participates in overload resolution only if
//          // 'OTHER' is implicitly convertible to 'TYPE'.
//
//      MyContainer(const MyContainer&  original,
//                  bslma::Allocator   *basicAllocator = 0);
//          // Create a container having the same value as the specified
//          // 'original' object.  Optionally specify a 'basicAllocator' used
//          // to supply memory.  If 'basicAllocator' is 0, the currently
//          // installed default allocator is used.
//
//      ~MyContainer();
//          // Destroy this object.
//
//      // MANIPULATORS
//      MyContainer& operator=(const TYPE& rhs);
//      MyContainer& operator=(const MyContainer& rhs);
//          // Assign to this object the value of the specified 'rhs' object,
//          // and return a reference providing modifiable access to this
//          // object.
//
//      TYPE& front()
//          // Return a non-'const' reference to the element contained in this
//          // object.
//      {
//          return *d_value_p;
//      }
//
//      // ACCESSORS
//      const TYPE& front() const
//          // Return a 'const' reference to the element contained in this
//          // object.
//      {
//          return *d_value_p;
//      }
//
//      bslma::Allocator *allocator() const
//          // Return the allocator used by this object to supply memory.
//      {
//          return d_allocator_p;
//      }
//
//      // etc.
//  };
//..
// Next, we implement the constructors that allocate memory and construct a
// 'TYPE' object in the allocated memory.  We perform the allocation using the
// 'allocate' method of 'bslma::Allocator' and the construction using the
// 'construct' method of 'ConstructionUtil' that provides the correct semantics
// for passing the allocator to the constructed object when appropriate:
//..
//  template <class TYPE>
//  MyContainer<TYPE>::MyContainer(bslma::Allocator *basicAllocator)
//  : d_allocator_p(bslma::Default::allocator(basicAllocator))
//  {
//      d_value_p = static_cast<TYPE *>(d_allocator_p->allocate(sizeof(TYPE)));
//      MyContainerProctor<TYPE> proctor(d_allocator_p, d_value_p);
//
//      // Call 'construct' with no constructor arguments (aside from the
//      // allocator).
//
//      bslma::ConstructionUtil::construct(d_value_p, d_allocator_p);
//      proctor.release();
//  }
//
//  template <class TYPE>
//  template <class OTHER>
//  MyContainer<TYPE>::MyContainer(
//                    BSLS_COMPILERFEATURES_FORWARD_REF(OTHER)  value,
//                    bslma::Allocator                         *basicAllocator)
//  : d_allocator_p(bslma::Default::allocator(basicAllocator))
//  {
//      d_value_p = static_cast<TYPE *>(d_allocator_p->allocate(sizeof(TYPE)));
//      MyContainerProctor<TYPE> proctor(d_allocator_p, d_value_p);
//
//      // Call 'construct' by forwarding 'value'.
//
//      bslma::ConstructionUtil::construct(
//          d_value_p,
//          d_allocator_p,
//          BSLS_COMPILERFEATURES_FORWARD(OTHER, value));
//      proctor.release();
//  }
//..
// Then, we define the copy constructor for 'MyContainer'.  Note that we don't
// propagate the allocator from the 'original' container, but use
// 'basicAllocator' instead:
//..
//  template <class TYPE>
//  MyContainer<TYPE>::MyContainer(const MyContainer&  original,
//                                 bslma::Allocator   *basicAllocator)
//  : d_allocator_p(bslma::Default::allocator(basicAllocator))
//  {
//      d_value_p = static_cast<TYPE *>(d_allocator_p->allocate(sizeof(TYPE)));
//      MyContainerProctor<TYPE> proctor(d_allocator_p, d_value_p);
//
//      // Call 'construct' so as to copy-construct the element contained by
//      // 'original'.
//
//      bslma::ConstructionUtil::construct(d_value_p,
//                                         d_allocator_p,
//                                         *original.d_value_p);
//      proctor.release();
//  }
//..
// Now, the destructor destroys the object and deallocates the memory used to
// hold the element using the allocator:
//..
//  template <class TYPE>
//  MyContainer<TYPE>::~MyContainer()
//  {
//      d_value_p->~TYPE();
//      d_allocator_p->deallocate(d_value_p);
//  }
//..
// Next, the assignment operator needs to assign the value without modifying
// the allocator.
//..
//  template <class TYPE>
//  MyContainer<TYPE>& MyContainer<TYPE>::operator=(const TYPE& rhs)
//  {
//      *d_value_p = rhs;
//      return *this;
//  }
//
//  template <class TYPE>
//  MyContainer<TYPE>& MyContainer<TYPE>::operator=(const MyContainer& rhs)
//  {
//      *d_value_p = *rhs.d_value_p;
//      return *this;
//  }
//..
// Finally, we perform a simple test of 'MyContainer', instantiating it with
// element type 'int':
//..
//  int main()
//  {
//      bslma::TestAllocator testAlloc;
//      MyContainer<int>     C1(123, &testAlloc);
//      assert(C1.allocator() == &testAlloc);
//      assert(C1.front()     == 123);
//
//      MyContainer<int> C2(C1);
//      assert(C2.allocator() == bslma::Default::defaultAllocator());
//      assert(C2.front()     == 123);
//
//      return 0;
//  }
//..
//
///Example 2: 'bslma' Allocator Propagation
///- - - - - - - - - - - - - - - - - - - -
// This example demonstrates that 'MyContainer' does indeed propagate the
// allocator to its contained element.
//
// First, we create a representative element class, 'MyType', that allocates
// memory using the 'bslma' allocator protocol:
//..
//  #include <bslma_default.h>
//
//  class MyType {
//
//      // DATA
//      // ...
//      bslma::Allocator *d_allocator_p;
//
//    public:
//      // TRAITS
//      BSLMF_NESTED_TRAIT_DECLARATION(MyType, bslma::UsesBslmaAllocator);
//
//      // CREATORS
//      explicit MyType(bslma::Allocator *basicAllocator = 0)
//          // Create a 'MyType' object having the default value.  Optionally
//          // specify a 'basicAllocator' used to supply memory.  If
//          // 'basicAllocator' is 0, the currently installed default allocator
//          // is used.
//      : d_allocator_p(bslma::Default::allocator(basicAllocator))
//      {
//          // ...
//      }
//
//      MyType(const MyType& original, bslma::Allocator *basicAllocator = 0)
//          // Create a 'MyType' object having the same value as the specified
//          // 'original' object.  Optionally specify a 'basicAllocator' used
//          // to supply memory.  If 'basicAllocator' is 0, the currently
//          // installed default allocator is used.
//      : d_allocator_p(bslma::Default::allocator(basicAllocator))
//      {
//          (void) original;
//          // ...
//      }
//
//      // ...
//
//      // ACCESSORS
//      bslma::Allocator *allocator() const
//          // Return the allocator used by this object to supply memory.
//      {
//          return d_allocator_p;
//      }
//
//      // ...
//  };
//..
// Finally, we instantiate 'MyContainer' using 'MyType' and verify that, when
// we provide the address of an allocator to the constructor of the container,
// the same address is passed to the constructor of the contained element.  We
// also verify that, when the container is copy-constructed without supplying
// an allocator, the copy uses the default allocator, not the allocator from
// the original object.  Moreover, we verify that the element stored in the
// copy also uses the default allocator:
//..
//  int main()
//  {
//      bslma::TestAllocator testAlloc;
//      MyContainer<MyType>  C1(&testAlloc);
//      assert(C1.allocator()         == &testAlloc);
//      assert(C1.front().allocator() == &testAlloc);
//
//      MyContainer<MyType> C2(C1);
//      assert(C2.allocator()         != C1.allocator());
//      assert(C2.allocator()         == bslma::Default::defaultAllocator());
//      assert(C2.front().allocator() != &testAlloc);
//      assert(C2.front().allocator() == bslma::Default::defaultAllocator());
//
//      return 0;
//  }
//..
//
///Example 3: Constructing into Non-heap Memory
///- - - - - - - - - - - - - - - - - - - - - -
// This example demonstrates using 'bslma::ConstructionUtil::make' to
// implement a simple wrapper class that contains a single item that might or
// might not use the 'bslma' allocator protocol.
//
// First, we define a wrapper class that holds an object and a functor and
// calls the functor (called the listener) each time the wrapped object is
// changed.  We store the object directly as a member variable, instead of
// using an uninitialized buffer, to avoid a separate construction step:
//..
//  template <class TYPE, class FUNC>
//  class MyTriggeredWrapper {
//      // This class is a wrapper around an object of the specified 'TYPE'
//      // that triggers a call to an object, called the "listener", of the
//      // specified 'FUNC' invocable type whenever the wrapped object is
//      // changed.
//
//      // DATA
//      TYPE d_value;
//      FUNC d_listener;
//
//    public:
//      // CREATORS
//      explicit MyTriggeredWrapper(const FUNC&       f,
//                                  bslma::Allocator *basicAllocator = 0);
//      MyTriggeredWrapper(const TYPE&       v,
//                         const FUNC&       f,
//                         bslma::Allocator *basicAllocator = 0);
//          // Create an object with the specified 'f' as the listener to be
//          // called when a change is triggered.  Optionally specify 'v' as
//          // the wrapped value; otherwise the wrapped value is default
//          // constructed.  Optionally specify 'basicAllocator' to supply
//          // memory; otherwise the current default allocator is used.  If
//          // 'TYPE' is not allocator aware, 'basicAllocator' is ignored.
//
//      MyTriggeredWrapper(const MyTriggeredWrapper&  original,
//                         bslma::Allocator          *basicAllocator = 0);
//          // Create a copy of the specified 'original'.  Optionally specify
//          // 'basicAllocator' to supply memory; otherwise the current
//          // default allocator is used.
//
//      ~MyTriggeredWrapper()
//          // Destroy the wrapped object and listener.
//      {
//      }
//
//      // MANIPULATORS
//      MyTriggeredWrapper& operator=(const TYPE& rhs);
//      MyTriggeredWrapper& operator=(const MyTriggeredWrapper& rhs);
//          // Assign the wrapped value to the value of the specified 'rhs',
//          // invoke the listener with the new value, and return a reference
//          // providing modifiable access to this object.  Note that the
//          // listener itself is not assigned.
//
//      void setValue(const TYPE& value);
//          // Set the wrapped value to the specified 'value' and invoke the
//          // listener with the new value.
//
//      // ACCESSORS
//      const TYPE& value() const
//          // Return a reference providing read-only access to the wrapped
//          // value.
//      {
//          return d_value;
//      }
//
//      const FUNC& listener() const
//          // Return a reference providing read-only access to the listener.
//      {
//          return d_listener;
//      }
//  };
//..
// Next, we define the constructors such that they initialize 'd_value' using
// the specified allocator if and only if 'TYPE' accepts an allocator.  The
// 'bslma::ConstructionUtil::make' family of functions encapsulate all of the
// metaprogramming that detects whether or not 'TYPE' uses an allocator and,
// if so, which construction protocol it uses (allocator at the front or at
// the back of the argument list), making all three constructors straight-
// forward:
//..
//  template <class TYPE, class FUNC>
//  MyTriggeredWrapper<TYPE, FUNC>::MyTriggeredWrapper(
//                                            const FUNC&       f,
//                                            bslma::Allocator *basicAllocator)
//  : d_value(bslma::ConstructionUtil::make<TYPE>(basicAllocator))
//  , d_listener(f)
//  {
//  }
//
//  template <class TYPE, class FUNC>
//  MyTriggeredWrapper<TYPE, FUNC>::MyTriggeredWrapper(
//                                            const TYPE&       v,
//                                            const FUNC&       f,
//                                            bslma::Allocator *basicAllocator)
//  : d_value(bslma::ConstructionUtil::make<TYPE>(basicAllocator, v))
//  , d_listener(f)
//  {
//  }
//
//  template <class TYPE, class FUNC>
//  MyTriggeredWrapper<TYPE, FUNC>::MyTriggeredWrapper(
//                                   const MyTriggeredWrapper&  other,
//                                   bslma::Allocator          *basicAllocator)
//  : d_value(bslma::ConstructionUtil::make<TYPE>(basicAllocator,
//                                                other.value()))
//  , d_listener(other.d_listener)
//  {
//  }
//..
// Note that, in order for 'd_value' to be constructed with the correct
// allocator, the compiler must construct the result returned by 'make'
// directly into the 'd_value' variable, an optimization formerly known prior
// to C++17 as "copy elision".  This optimization is required by the C++17
// standard and is optional in pre-2017 standards, but is implemented in all
// of the compilers for which this component is expected to be used at
// Bloomberg.
//
// Next, we implement the assignment operators, which simply call 'setValue':
//..
//  template <class TYPE, class FUNC>
//  MyTriggeredWrapper<TYPE, FUNC>&
//  MyTriggeredWrapper<TYPE, FUNC>::operator=(const TYPE& rhs)
//  {
//      setValue(rhs);
//      return *this;
//  }
//
//  template <class TYPE, class FUNC>
//  MyTriggeredWrapper<TYPE, FUNC>&
//  MyTriggeredWrapper<TYPE, FUNC>::operator=(const MyTriggeredWrapper& rhs)
//  {
//      setValue(rhs.value());
//      return *this;
//  }
//..
// Then, we implement 'setValue', which calls the listener after modifying the
// value:
//..
//  template <class TYPE, class FUNC>
//  void MyTriggeredWrapper<TYPE, FUNC>::setValue(const TYPE& value)
//  {
//      d_value = value;
//      d_listener(d_value);
//  }
//..
// Finally, we check our work by creating a listener for 'MyContainer<int>'
// that stores its last-seen value in a known location and a wrapper around
// 'MyContainer<int>' to test it:
//..
//  int lastSeen = 0;
//  void myListener(const MyContainer<int>& c)
//  {
//      lastSeen = c.front();
//  }
//
//  void main()
//  {
//      bslma::TestAllocator testAlloc;
//      MyTriggeredWrapper<MyContainer<int>,
//                         void (*)(const MyContainer<int>&)>
//                           wrappedContainer(myListener, &testAlloc);
//      assert(&testAlloc == wrappedContainer.value().allocator());
//
//      wrappedContainer = MyContainer<int>(99);
//
//      assert(99 == lastSeen);
//  }
//..

#include <bslscm_version.h>

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

#include <bslmf_allocatorargt.h>
#include <bslmf_integralconstant.h>
#include <bslmf_isbitwisemoveable.h>
#include <bslmf_isempty.h>
#include <bslmf_isfundamental.h>
#include <bslmf_ismemberpointer.h>
#include <bslmf_ispointer.h>
#include <bslmf_istriviallycopyable.h>
#include <bslmf_istriviallydefaultconstructible.h>
#include <bslmf_movableref.h>
#include <bslmf_removecv.h>
#include <bslmf_usesallocatorargt.h>
#include <bslmf_util.h>    // 'forward(V)'

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_libraryfeatures.h>
#include <bsls_platform.h>
#include <bsls_util.h>     // 'forward<T>(V)'

#include <stddef.h>
#include <string.h>

#include <new>          // placement 'new'

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bslma_destructorproctor.h>
#endif

#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 bslma_constructionutil.h
# define COMPILING_BSLMA_CONSTRUCTIONUTIL_H
# include <bslma_constructionutil_cpp03.h>
# undef COMPILING_BSLMA_CONSTRUCTIONUTIL_H
#else

namespace BloombergLP {
namespace bslma {

// Workaround for optimization issue in xlC that mishandles pointer aliasing.
//   IV56864: ALIASING BEHAVIOUR FOR PLACEMENT NEW
//   http://www-01.ibm.com/support/docview.wss?uid=swg1IV56864
// Place this macro following each use of placement new.  Alternatively,
// compile with xlC_r -qalias=noansi, which reduces optimization opportunities
// across entire translation unit instead of simply across optimization fence.
// Update: issue is fixed in xlC 13.1 (__xlC__ >= 0x0d01).

#if defined(BSLS_PLATFORM_CMP_IBM) && BSLS_PLATFORM_CMP_VERSION < 0x0d01
    #define BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX                     \
                             BSLS_PERFORMANCEHINT_OPTIMIZATION_FENCE
#else
    #define BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX
#endif

struct ConstructionUtil_Imp;

                          // =======================
                          // struct ConstructionUtil
                          // =======================

struct ConstructionUtil {
    // This 'struct' provides a namespace for utility functions that construct
    // elements of (a template parameter) 'TARGET_TYPE'.

  private:
    // PRIVATE TYPES
    typedef ConstructionUtil_Imp Imp;
        // This 'typedef' is a convenient alias for the implementation-specific
        // utility class defined in this component.

  public:
    // CLASS METHODS
    template <class TARGET_TYPE>
    static void construct(TARGET_TYPE *address, bslma::Allocator *allocator);
    template <class TARGET_TYPE>
    static void construct(TARGET_TYPE *address, void *allocator);
        // Create a default-constructed object of (template parameter)
        // 'TARGET_TYPE' at the specified 'address'.  If 'allocator' is of type
        // 'bslma::Allocator' and 'TARGET_TYPE' supports 'bslma'-style
        // allocation, 'allocator' is passed to the default constructor.  If
        // the constructor throws, the memory at 'address' is left in an
        // unspecified state.  Note that this operation may bypass the call to
        // the default constructor of a user-defined type entirely if
        // 'TARGET_TYPE' 1) does not use 'bslma'-style allocators and 2) has a
        // trivial default constructor.

    template <class TARGET_TYPE>
    static void construct(TARGET_TYPE        *address,
                          bslma::Allocator   *allocator,
                          const TARGET_TYPE&  original);
    template <class TARGET_TYPE>
    static void
    construct(TARGET_TYPE *address, void *, const TARGET_TYPE& original);
    template <class TARGET_TYPE>
    static void construct(TARGET_TYPE        *address,
                          bslma::Allocator   *allocator,
                          TARGET_TYPE&        original);
    template <class TARGET_TYPE>
    static void
    construct(TARGET_TYPE *address, void *, TARGET_TYPE& original);
        // Create an object of (template parameter) 'TARGET_TYPE', having
        // the same value as the specified 'original' object, at the specified
        // 'address'.  If 'allocator' is of type 'bslma::Allocator' and
        // 'TARGET_TYPE' supports 'bslma'-style allocation, 'allocator' is
        // propagated to the newly created object.  If a constructor throws,
        // the memory at 'address' is left in an unspecified state.  Note that
        // this operation may elide the call to the copy constructor entirely
        // if 'TARGET_TYPE' 1) does not use 'bslma'-style allocators and 2) is
        // trivially copyable.  Further note that we provide (unconventional)
        // overloads for modifiable lvalues because these may match more
        // generic overloads (below) taking a variable number of deduced
        // template parameters.

    template <class TARGET_TYPE>
    static void construct(TARGET_TYPE                    *address,
                          bslma::Allocator               *allocator,
                          bslmf::MovableRef<TARGET_TYPE>  original);
    template <class TARGET_TYPE>
    static void construct(TARGET_TYPE                    *address,
                          void                           *allocator,
                          bslmf::MovableRef<TARGET_TYPE>  original);
        // Create an object of (template parameter) 'TARGET_TYPE', having
        // the same value as the specified 'original' object, at the specified
        // 'address'.  'original' is left in a valid but unspecified state.  If
        // the specified 'allocator' is of type 'bslma::Allocator' and
        // 'TARGET_TYPE' supports 'bslma'-style allocation, 'allocator' is
        // propagated to the newly created object.  If a constructor throws,
        // the memory at 'address' is left in an unspecified state.  Note that
        // this operation may elide the call to the copy constructor entirely
        // if 'TARGET_TYPE' 1) does not use 'bslma'-style allocators and 2) is
        // trivially copyable.  Further note that we provide (unconventional)
        // overloads for modifiable lvalues because these may match more
        // generic overloads (below) taking a variable number of deduced
        // template parameters.

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=15
    template <class TARGET_TYPE, class ARG1, class... ARGS>
    static void construct(TARGET_TYPE      *address,
                          bslma::Allocator *allocator,
                          ARG1&&            argument,
                          ARGS&&...         arguments);
    template <class TARGET_TYPE, class ARG1, class... ARGS>
    static void construct(TARGET_TYPE *address,
                          void        *allocator,
                          ARG1&&       argument,
                          ARGS&&...    arguments);
        // Create an object of (template parameter) 'TARGET_TYPE' at the
        // specified 'address', constructed by forwarding the specified
        // 'argument' and the (variable number of) additional specified
        // 'arguments' to the corresponding constructor of 'TARGET_TYPE'.  If
        // the specified 'allocator' is of type 'bslma::Allocator *' and
        // 'TARGET_TYPE' supports 'bslma'-style allocation, the allocator is
        // passed to the constructor (as the last argument).  If the
        // constructor throws, the memory at 'address' is left in an
        // unspecified state.
#endif

    template <class TARGET_TYPE, class ALLOCATOR>
    static void destructiveMove(TARGET_TYPE *address,
                                ALLOCATOR   *allocator,
                                TARGET_TYPE *original);
        // Create an object of (template parameter) 'TARGET_TYPE' at the
        // specified 'address' having the same value as the object at the
        // specified 'original' address, propagating the specified 'allocator'
        // to the moved object if 'TARGET_TYPE' uses 'bslma'-style allocation
        // and the (template parameter) type 'ALLOCATOR' is implicitly
        // convertible to 'bslma::Allocator', and destroy 'original'.  If the
        // move constructor throws an exception, the memory at 'address' is
        // left in an unspecified state and 'original' is left in a valid but
        // unspecified state.  The behavior is undefined unless either
        // 'TARGET_TYPE' does not support 'bslma'-style allocation or
        // 'original' uses 'allocator' to supply memory.  Note that this class
        // method is equivalent to move-constructing an object at 'address'
        // from '*original' and then destroying 'original', except that this
        // method elides the calls to the constructor and destructor for
        // objects that are bitwise movable.  Also note that if 'original'
        // actually points to an object of a type derived from 'TARGET_TYPE'
        // (i.e., a slicing move) where 'TARGET_TYPE' has a non-'virtual'
        // destructor and is not bitwise-movable, then 'original' will be only
        // partially destroyed.

#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
    template <class TARGET_TYPE>
    static TARGET_TYPE make(bslma::Allocator *allocator);
    template <class TARGET_TYPE>
    static TARGET_TYPE make(void             *allocator);
        // Return, by value, an object of the specified (template parameter)
        // 'TARGET_TYPE', having default value.  If the specified 'allocator'
        // is a pointer to a class derived from 'bslma::Allocator *' and
        // 'TARGET_TYPE' supports 'bslma'-style allocation, 'allocator' is
        // propagated to the newly created object; otherwise, 'allocator' is
        // ignored.  Note that this method is available only for compilers that
        // reliably implement copy/move elision (i.e., RVO) on the returned
        // object.  This copy/move elision is required starting with C++17 and
        // is widely implemented, though optional, prior to C++17.

    template <class TARGET_TYPE, class ANY_TYPE>
    static TARGET_TYPE make(
                        bslma::Allocator                            *allocator,
                        BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)  argument);
    template <class TARGET_TYPE,class ANY_TYPE>
    static TARGET_TYPE make(
                        void                                        *allocator,
                        BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)  argument);
        // Return, by value, an object of the specified (template parameter)
        // 'TARGET_TYPE', constructed from the specified 'argument'.  If the
        // specified 'allocator' is a pointer to a class derived from
        // 'bslma::Allocator *' and 'TARGET_TYPE' supports 'bslma'-style
        // allocation, 'allocator' is propagated to the newly created object;
        // otherwise, 'allocator' is ignored.  Note that this method is
        // available only for compilers that reliably implement copy/move
        // elision (i.e., RVO) on the returned object.  This copy/move elision
        // is required starting with C++17 and is widely implemented, though
        // optional, prior to C++17.

#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)

};
                        // ===========================
                        // struct ConstructionUtil_Imp
                        // ===========================

struct ConstructionUtil_Imp {
    // This 'struct' provides a namespace for a suite of utility functions that
    // are used to implement functions in 'ConstructionUtil'.  In particular,
    // they provide overloads, resolved at compile-time, for various features
    // (e.g., passing down the allocator to sub-elements of 'pair'-like types)
    // and optimizations (e.g., bypassing the call to the constructor for
    // classes with trivial default and copy constructors).  These functions
    // should not be used outside this component.

    // TYPES
    enum {
        // These constants are used in the overloads below, when the last
        // argument is of type 'bsl::integral_constant<int, N> *', indicating
        // that 'TARGET_TYPE' has the traits for which the enumerator equal to
        // 'N' is named.

        e_USES_ALLOCATOR_ARG_T_TRAITS     = 5, // Implies USES_BSLMA_ALLOCATOR
        e_USES_BSLMA_ALLOCATOR_TRAITS     = 4,
        e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS = 3,
        e_BITWISE_COPYABLE_TRAITS         = 2,
        e_BITWISE_MOVABLE_TRAITS          = 1,
        e_NIL_TRAITS                      = 0
    };

    // CLASS METHODS
    template <class TARGET_TYPE>
    static void construct(
             TARGET_TYPE      *address,
             bslma::Allocator *allocator,
             bsl::integral_constant<int, e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS> *);

    template <class TARGET_TYPE>
    static void construct(
             TARGET_TYPE *address,
             bsl::integral_constant<int, e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS> *);
        // Construct a default instance of (template parameter) 'TARGET_TYPE'
        // that has a trivial default constructor, at the specified 'address'.
        // If the constructor throws, the memory at 'address' is left in an
        // unspecified state.  Note that the behavior is undefined if
        // 'TARGET_TYPE' supports 'bslma'-style allocators.

    // In order to implement:
    //   'allocator_traits<A>::construct(m, p, rv)'
    //   'allocator_traits<A>::construct(m, p,  v)'
    // if 'e_BITWISE_COPYABLE_TRAITS'.

    template <class TARGET_TYPE>
    static void
    construct(TARGET_TYPE        *address,
              bslma::Allocator   *allocator,
              bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
              const TARGET_TYPE&  original);

    template <class TARGET_TYPE>
    static void
    construct(TARGET_TYPE        *address,
              bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
              const TARGET_TYPE&  original);
        // Create an object of a bitwise copyable (template parameter)
        // 'TARGET_TYPE' at the specified 'address', with the same value as the
        // specified 'original' object.  If the constructor throws, the memory
        // at 'address' is left in an unspecified state.  Note that the
        // behavior is undefined if 'TARGET_TYPE' supports 'bslma'-style
        // allocators.

    template <class TARGET_TYPE>
    static void
    construct(
             TARGET_TYPE                                            *address,
             bslma::Allocator                                       *allocator,
             bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
             bslmf::MovableRef<TARGET_TYPE>                          original);
    template <class TARGET_TYPE>
    static void
    construct(
             TARGET_TYPE                                            *address,
             bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
             bslmf::MovableRef<TARGET_TYPE>                          original);
        // Create an object of a bitwise moveable (template parameter)
        // 'TARGET_TYPE' at the specified 'address', with the same value as the
        // specified 'original' object.  If the constructor throws, the memory
        // at 'address' is left in an unspecified state.  Note that the
        // behavior is undefined if 'TARGET_TYPE' supports 'bslma'-style
        // allocators.

    // In order to implement:
    //   'allocator_traits<A>::construct(m, p    )'
    //   'allocator_traits<A>::construct(m, p, rv)'
    //   'allocator_traits<A>::construct(m, p,  v)'
    // if 'e_USES_BSLMA_ALLOCATOR_TRAITS', and:
    //   'allocator_traits<A>::construct(m, p, args)'

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=15
    template <class TARGET_TYPE, class... ARGS>
    static void construct(
                  TARGET_TYPE      *address,
                  bslma::Allocator *allocator,
                  bsl::integral_constant<int, e_USES_BSLMA_ALLOCATOR_TRAITS> *,
                  ARGS&&...         arguments);
    template <class TARGET_TYPE, class... ARGS>
    static void construct(
                  TARGET_TYPE      *address,
                  bslma::Allocator *allocator,
                  bsl::integral_constant<int, e_USES_ALLOCATOR_ARG_T_TRAITS> *,
                  ARGS&&...         arguments);
        // Construct an object at the specified 'address' having the specified
        // (template parameter) 'TARGET_TYPE' that supports 'bslma'-style
        // allocators.  Invoke the constructor of 'TARGET_TYPE' using the
        // specified 'arguments'.  For the 'e_USES_BSLMA_ALLOCATOR_TRAITS'
        // overload, the specified 'allocator' is passed as an additional last
        // argument to the constructor.  For the
        // 'e_USES_ALLOCATOR_ARG_T_TRAITS' overload, the 'allocator' is passed
        // as the second argument to the constructor, preceded by
        // 'bsl::allocator_arg'.  If the constructor throws, the memory at
        // 'address' is left in an uninitialized state.

    template <class TARGET_TYPE, class... ARGS>
    static void construct(TARGET_TYPE      *address,
                          bslma::Allocator *allocator,
                          bsl::integral_constant<int, e_NIL_TRAITS> *,
                          ARGS&&...         arguments);

    template <class TARGET_TYPE, class... ARGS>
    static void construct(TARGET_TYPE      *address,
                          bsl::integral_constant<int, e_NIL_TRAITS> *,
                          ARGS&&...         arguments);
        // Construct an object of (template parameter) 'TARGET_TYPE', that does
        // not support 'bslma'-style allocators, at the specified 'address',
        // invoking the constructor of 'TARGET_TYPE' corresponding to the
        // specified 'arguments'.  If the constructor throws, the memory at
        // 'address' is left in an unspecified state.
#endif

#if defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION < 1900
    template <class TARGET_TYPE>
    static void defaultConstructScalar(bsl::false_type, TARGET_TYPE *address);
        // Value-initialize a scalar object of the (template parameter)
        // 'TARGET_TYPE' at the specified 'address'.  The unused
        // 'bsl::false_type' value indicates that the scalar 'TARGET_TYPE' is
        // not a pointer-to-member.

    template <class TARGET_TYPE>
    static void defaultConstructScalar(bsl::true_type, TARGET_TYPE *address);
        // Value-initialize a pointer-to-member at the specified 'address' to
        // the null pointer value.  Note that early versions of the Microsoft
        // Visual C++ compiler would fail to initialize such an object when
        // requested with the simple value-initialization syntax of
        // 'new (address) TYPE();', requiring this additional workaround.
#endif

    template <class TARGET_TYPE, class ALLOCATOR>
    static void destructiveMove(
              TARGET_TYPE                                           *address,
              ALLOCATOR                                             *allocator,
              bsl::integral_constant<int, e_BITWISE_MOVABLE_TRAITS> *,
              TARGET_TYPE                                           *original);
        // Move the bitwise movable object of (template parameter)
        // 'TARGET_TYPE' at the specified 'original' address to the specified
        // 'address', eliding the call to the move constructor and destructor
        // in favor of performing a bitwise copy.  The behavior is undefined
        // unless either 'TARGET_TYPE' does not support 'bslma'-style
        // allocation or 'original' uses the specified 'allocator' to supply
        // memory.

    template <class TARGET_TYPE, class ALLOCATOR>
    static void destructiveMove(
                          TARGET_TYPE                               *address,
                          ALLOCATOR                                 *allocator,
                          bsl::integral_constant<int, e_NIL_TRAITS> *,
                          TARGET_TYPE                               *original);
        // Create an object of (template parameter) 'TARGET_TYPE' at the
        // specified 'address' having the same value as the object at the
        // specified 'original' address, propagating the specified 'allocator'
        // to the moved object if 'TARGET_TYPE' uses 'bslma'-style allocation
        // and the (template parameter) type 'ALLOCATOR' is implicitly
        // convertible to 'bslma::Allocator', and destroy 'original'.  If the
        // move constructor throws an exception, the memory at 'address' is
        // left in an unspecified state and 'original' is left in a valid but
        // unspecified state.  The behavior is undefined unless either
        // 'TARGET_TYPE' does not support 'bslma'-style allocation or
        // 'original' uses 'allocator' to supply memory.  Note that this class
        // method is equivalent to move-constructing an object at 'address'
        // from '*original' and then destroying 'original'.  Also note that if
        // 'original' actually points to an object of a type derived from
        // 'TARGET_TYPE' (i.e., a slicing move) where 'TARGET_TYPE' has a
        // non-'virtual' destructor, then 'original' will be only partially
        // destroyed.

#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
    template <class TARGET_TYPE>
    static TARGET_TYPE make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_BSLMA_ALLOCATOR_TRAITS> *);
    template <class TARGET_TYPE>
    static TARGET_TYPE make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_ALLOCATOR_ARG_T_TRAITS> *);
    template <class TARGET_TYPE>
    static TARGET_TYPE make(bslma::Allocator *allocator,
                            bsl::integral_constant<int, e_NIL_TRAITS> *);
        // Return, by value, a default-constructed object of the specified
        // (template parameter) 'TARGET_TYPE', using the specified 'allocator'
        // to supply memory.  The 'integral_constant' pointer argument is used
        // to dispatch on various traits so that the correct constructor is
        // invoked for the specified 'TARGET_TYPE'.

    template <class TARGET_TYPE, class ANY_TYPE>
    static TARGET_TYPE make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_BSLMA_ALLOCATOR_TRAITS> *,
         BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)                 argument);
    template <class TARGET_TYPE, class ANY_TYPE>
    static TARGET_TYPE make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_ALLOCATOR_ARG_T_TRAITS> *,
         BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)                 argument);
    template <class TARGET_TYPE, class ANY_TYPE>
    static TARGET_TYPE make(
                        bslma::Allocator                            *allocator,
                        bsl::integral_constant<int, e_NIL_TRAITS>   *,
                        BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)  argument);
        // Return, by value, an object of the specified (template parameter)
        // 'TARGET_TYPE', constructed from the specified 'argument' object,
        // using the specified 'allocator' to supply memory.  The
        // 'integral_constant' pointer argument is used to dispatch on various
        // traits so that the correct constructor is invoked for the specified
        // 'TARGET_TYPE'.

#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)

    template <class TARGET_TYPE>
    static void *voidify(TARGET_TYPE *address);
        // Return the specified 'address' cast as a pointer to 'void', even if
        // the (template parameter) 'TARGET_TYPE' is cv-qualified.
};

// ============================================================================
//                      TEMPLATE FUNCTION DEFINITIONS
// ============================================================================

                          // -----------------------
                          // struct ConstructionUtil
                          // -----------------------

// CLASS METHODS
template <class TARGET_TYPE>
inline
void
ConstructionUtil::construct(TARGET_TYPE      *address,
                            bslma::Allocator *allocator)
{
    enum {
        k_VALUE = bslma::UsesBslmaAllocator<TARGET_TYPE>::value
                ? (bslmf::UsesAllocatorArgT<TARGET_TYPE>::value
                 ? Imp::e_USES_ALLOCATOR_ARG_T_TRAITS
                 : Imp::e_USES_BSLMA_ALLOCATOR_TRAITS)
                : bsl::is_trivially_default_constructible<TARGET_TYPE>::value
                    ? Imp::e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS
                    : Imp::e_NIL_TRAITS
    };
    Imp::construct(address,
                   allocator,
                   (bsl::integral_constant<int, k_VALUE>*)0);
}

template <class TARGET_TYPE>
inline
void
ConstructionUtil::construct(TARGET_TYPE *address,
                            void        *)
{
    enum {
        k_VALUE = bsl::is_trivially_default_constructible<TARGET_TYPE>::value
                ? Imp::e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS
                : Imp::e_NIL_TRAITS
    };
    Imp::construct(address, (bsl::integral_constant<int, k_VALUE>*)0);
}

template <class TARGET_TYPE>
inline
void ConstructionUtil::construct(TARGET_TYPE        *address,
                                 bslma::Allocator   *allocator,
                                 const TARGET_TYPE&  original)
{
    enum {
        k_VALUE = bslma::UsesBslmaAllocator<TARGET_TYPE>::value
                ? (bslmf::UsesAllocatorArgT<TARGET_TYPE>::value
                 ? Imp::e_USES_ALLOCATOR_ARG_T_TRAITS
                 : Imp::e_USES_BSLMA_ALLOCATOR_TRAITS)
                : bsl::is_trivially_copyable<TARGET_TYPE>::value
                    ? Imp::e_BITWISE_COPYABLE_TRAITS
                    : Imp::e_NIL_TRAITS
    };
    Imp::construct(address,
                   allocator,
                   (bsl::integral_constant<int, k_VALUE> *)0,
                   original);
}

template <class TARGET_TYPE>
inline
void ConstructionUtil::construct(TARGET_TYPE      *address,
                                 bslma::Allocator *allocator,
                                 TARGET_TYPE&      original)
{
    enum {
        k_VALUE = bslma::UsesBslmaAllocator<TARGET_TYPE>::value
                ? (bslmf::UsesAllocatorArgT<TARGET_TYPE>::value
                 ? Imp::e_USES_ALLOCATOR_ARG_T_TRAITS
                 : Imp::e_USES_BSLMA_ALLOCATOR_TRAITS)
                : bsl::is_trivially_copyable<TARGET_TYPE>::value
                    ? Imp::e_BITWISE_COPYABLE_TRAITS
                    : Imp::e_NIL_TRAITS
    };
    Imp::construct(address,
                   allocator,
                   (bsl::integral_constant<int, k_VALUE> *)0,
                   original);
}

template <class TARGET_TYPE>
inline
void ConstructionUtil::construct(TARGET_TYPE        *address,
                                 void               *,
                                 const TARGET_TYPE&  original)
{
    enum {
        k_VALUE = bsl::is_trivially_copyable<TARGET_TYPE>::value
                ? Imp::e_BITWISE_COPYABLE_TRAITS
                : Imp::e_NIL_TRAITS
    };
    Imp::construct(address,
                   (bsl::integral_constant<int, k_VALUE>*)0,
                   original);
}

template <class TARGET_TYPE>
inline
void ConstructionUtil::construct(TARGET_TYPE  *address,
                                 void         *,
                                 TARGET_TYPE&  original)
{
    enum {
        k_VALUE = bsl::is_trivially_copyable<TARGET_TYPE>::value
                ? Imp::e_BITWISE_COPYABLE_TRAITS
                : Imp::e_NIL_TRAITS
    };
    Imp::construct(address,
                   (bsl::integral_constant<int, k_VALUE>*)0,
                   original);
}

template <class TARGET_TYPE>
inline
void ConstructionUtil::construct(TARGET_TYPE                    *address,
                                 bslma::Allocator               *allocator,
                                 bslmf::MovableRef<TARGET_TYPE>  original)
{
    enum {
        k_VALUE = bslma::UsesBslmaAllocator<TARGET_TYPE>::value
                ? (bslmf::UsesAllocatorArgT<TARGET_TYPE>::value
                 ? Imp::e_USES_ALLOCATOR_ARG_T_TRAITS
                 : Imp::e_USES_BSLMA_ALLOCATOR_TRAITS)
                : bsl::is_trivially_copyable<TARGET_TYPE>::value
                 ? Imp::e_BITWISE_COPYABLE_TRAITS
                 : Imp::e_NIL_TRAITS
    };
    Imp::construct(address,
                   allocator,
                   (bsl::integral_constant<int, k_VALUE> *)0,
                   BSLS_COMPILERFEATURES_FORWARD(TARGET_TYPE, original));
}

template <class TARGET_TYPE>
inline
void ConstructionUtil::construct(TARGET_TYPE                    *address,
                                 void                           *,
                                 bslmf::MovableRef<TARGET_TYPE>  original)
{

    enum {
        k_VALUE = bsl::is_trivially_copyable<TARGET_TYPE>::value
                ? Imp::e_BITWISE_COPYABLE_TRAITS
                : Imp::e_NIL_TRAITS
    };

    Imp::construct(address,
                   (bsl::integral_constant<int, k_VALUE>*)0,
                   BSLS_COMPILERFEATURES_FORWARD(TARGET_TYPE, original));
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=15
template <class TARGET_TYPE, class ARG1, class... ARGS>
inline
void
ConstructionUtil::construct(TARGET_TYPE      *address,
                            bslma::Allocator *allocator,
                            ARG1&&            argument1,
                            ARGS&&...         arguments)
{
    enum {
        k_VALUE = bslma::UsesBslmaAllocator<TARGET_TYPE>::value
                ? (bslmf::UsesAllocatorArgT<TARGET_TYPE>::value
                 ? Imp::e_USES_ALLOCATOR_ARG_T_TRAITS
                 : Imp::e_USES_BSLMA_ALLOCATOR_TRAITS)
                : Imp::e_NIL_TRAITS
    };
    Imp::construct(address,
                   allocator,
                   (bsl::integral_constant<int, k_VALUE>*)0,
                   BSLS_COMPILERFEATURES_FORWARD(ARG1,argument1),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS,arguments)...);
}

template <class TARGET_TYPE, class ARG1, class... ARGS>
inline
void
ConstructionUtil::construct(TARGET_TYPE *address,
                            void        *,
                            ARG1&&       argument1,
                            ARGS&&...    arguments)
{
    ::new (Imp::voidify(address)) TARGET_TYPE(
                             BSLS_COMPILERFEATURES_FORWARD(ARG1,argument1),
                             BSLS_COMPILERFEATURES_FORWARD(ARGS,arguments)...);
    BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX;
}
#endif

template <class TARGET_TYPE, class ALLOCATOR>
inline
void
ConstructionUtil::destructiveMove(TARGET_TYPE *address,
                                  ALLOCATOR   *allocator,
                                  TARGET_TYPE *original)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(original);

    enum {
        k_VALUE = bslmf::IsBitwiseMoveable<TARGET_TYPE>::value
                ? Imp::e_BITWISE_MOVABLE_TRAITS
                : Imp::e_NIL_TRAITS
    };

    Imp::destructiveMove(address,
                         allocator,
                         (bsl::integral_constant<int, k_VALUE>*)0,
                         original);
}

#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
// Suppress bde_verify warnings about return-by-value in this region.
// BDE_VERIFY pragma: push
// BDE_VERIFY pragma: -AR01: Type using allocator is returned by value

template <class TARGET_TYPE>
inline
TARGET_TYPE
ConstructionUtil::make(bslma::Allocator *allocator)
{
    enum {
        k_VALUE = bslma::UsesBslmaAllocator<TARGET_TYPE>::value
                ? (bslmf::UsesAllocatorArgT<TARGET_TYPE>::value
                   ? Imp::e_USES_ALLOCATOR_ARG_T_TRAITS
                   : Imp::e_USES_BSLMA_ALLOCATOR_TRAITS)
                : Imp::e_NIL_TRAITS
    };

    return Imp::make<TARGET_TYPE>(allocator,
                                  (bsl::integral_constant<int, k_VALUE> *) 0);
}

template <class TARGET_TYPE>
inline
TARGET_TYPE
ConstructionUtil::make(void *)
{
    return TARGET_TYPE();
}

template <class TARGET_TYPE, class ANY_TYPE>
inline
TARGET_TYPE
ConstructionUtil::make(bslma::Allocator                            *allocator,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)  argument)
{
    enum {
        k_VALUE = bslma::UsesBslmaAllocator<TARGET_TYPE>::value
                ? (bslmf::UsesAllocatorArgT<TARGET_TYPE>::value
                   ? Imp::e_USES_ALLOCATOR_ARG_T_TRAITS
                   : Imp::e_USES_BSLMA_ALLOCATOR_TRAITS)
                : Imp::e_NIL_TRAITS
    };

    return Imp::make<TARGET_TYPE>(allocator,
                                  (bsl::integral_constant<int, k_VALUE> *) 0,
                                  BSLS_COMPILERFEATURES_FORWARD(ANY_TYPE,
                                                                argument));
}

template <class TARGET_TYPE, class ANY_TYPE>
inline
TARGET_TYPE
ConstructionUtil::make(void                                        *,
                       BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)  argument)
{
    return TARGET_TYPE(BSLS_COMPILERFEATURES_FORWARD(ANY_TYPE, argument));
}

// BDE_VERIFY pragma: pop
#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)

                       // ---------------------------
                       // struct ConstructionUtil_Imp
                       // ---------------------------

// CLASS METHODS
template <class TARGET_TYPE>
inline
void
ConstructionUtil_Imp::construct(
              TARGET_TYPE *address,
              bslma::Allocator *,
              bsl::integral_constant<int, e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS> *)
{
    construct(address,
              (bsl::integral_constant<int,
                                      e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS> *) 0);
}

template <class TARGET_TYPE>
inline
void
ConstructionUtil_Imp::construct(
              TARGET_TYPE *address,
              bsl::integral_constant<int, e_HAS_TRIVIAL_DEFAULT_CTOR_TRAITS> *)
{
#if defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION < 1900
    defaultConstructScalar(bsl::is_member_pointer<TARGET_TYPE>(), address);
#else
    ::new (voidify(address)) TARGET_TYPE();
    BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX;
#endif
}

template <class TARGET_TYPE>
inline
void ConstructionUtil_Imp::construct(
              TARGET_TYPE                                            *address,
              bslma::Allocator                                       *,
              bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
              const TARGET_TYPE&                                      original)
{
    construct(address,
              (bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS>*)0,
               original);
}

template <class TARGET_TYPE>
inline
void ConstructionUtil_Imp::construct(
              TARGET_TYPE                                            *address,
              bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
              const TARGET_TYPE&                                      original)
{
    ::new (voidify(address)) TARGET_TYPE(original);
    BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX;
}

template <class TARGET_TYPE>
inline
void ConstructionUtil_Imp::construct(
              TARGET_TYPE                                            *address,
              bslma::Allocator                                       *,
              bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
              bslmf::MovableRef<TARGET_TYPE>                          original)
{
    construct(address,
              (bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS>*)0,
              BSLS_COMPILERFEATURES_FORWARD(TARGET_TYPE, original));
}

template <class TARGET_TYPE>
inline
void ConstructionUtil_Imp::construct(
              TARGET_TYPE                                            *address,
              bsl::integral_constant<int, e_BITWISE_COPYABLE_TRAITS> *,
              bslmf::MovableRef<TARGET_TYPE>                          original)
{
    ::new (voidify(address)) TARGET_TYPE(BSLS_COMPILERFEATURES_FORWARD(
        TARGET_TYPE, bslmf::MovableRefUtil::move(original)));
}

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=15
template <class TARGET_TYPE, class... ARGS>
inline
void
ConstructionUtil_Imp::construct(
         TARGET_TYPE                                                *address,
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_BSLMA_ALLOCATOR_TRAITS> *,
         ARGS&&...                                                   arguments)
{
    ::new (voidify(address)) TARGET_TYPE(
                  BSLS_COMPILERFEATURES_FORWARD(ARGS,arguments)..., allocator);
    BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX;
}

template <class TARGET_TYPE, class... ARGS>
inline
void
ConstructionUtil_Imp::construct(
         TARGET_TYPE                                                *address,
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_ALLOCATOR_ARG_T_TRAITS> *,
         ARGS&&...                                                   arguments)
{
    ::new (voidify(address)) TARGET_TYPE(
                             bsl::allocator_arg,
                             allocator,
                             BSLS_COMPILERFEATURES_FORWARD(ARGS,arguments)...);
    BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX;
}

template <class TARGET_TYPE, class... ARGS>
inline
void
ConstructionUtil_Imp::construct(
                          TARGET_TYPE                               *address,
                          bslma::Allocator                          *,
                          bsl::integral_constant<int, e_NIL_TRAITS> *,
                          ARGS&&...                                  arguments)
{
    construct(address,
              (bsl::integral_constant<int, e_NIL_TRAITS> *)0,
              BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
}

template <class TARGET_TYPE, class... ARGS>
inline
void
ConstructionUtil_Imp::construct(
                          TARGET_TYPE                               *address,
                          bsl::integral_constant<int, e_NIL_TRAITS> *,
                          ARGS&&...                                  arguments)
{
    ::new (voidify(address)) TARGET_TYPE(
                             BSLS_COMPILERFEATURES_FORWARD(ARGS,arguments)...);
    BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX;
}
#endif

#if defined(BSLS_PLATFORM_CMP_MSVC) && BSLS_PLATFORM_CMP_VERSION < 1900
template <class TARGET_TYPE>
inline
void
ConstructionUtil_Imp::defaultConstructScalar(bsl::false_type,
                                             TARGET_TYPE *address)
{
    ::new (voidify(address)) TARGET_TYPE();
}

template <class TARGET_TYPE>
inline
void
ConstructionUtil_Imp::defaultConstructScalar(bsl::true_type,
                                             TARGET_TYPE *address)
{
    ::new (voidify(address)) TARGET_TYPE(nullptr);
}
#endif

template <class TARGET_TYPE, class ALLOCATOR>
inline
void
ConstructionUtil_Imp::destructiveMove(
               TARGET_TYPE                                           *address,
               ALLOCATOR                                             *,
               bsl::integral_constant<int, e_BITWISE_MOVABLE_TRAITS> *,
               TARGET_TYPE                                           *original)
{
    if (bsl::is_fundamental<TARGET_TYPE>::value ||
        bsl::is_pointer<TARGET_TYPE>::value) {
        ::new (voidify(address)) TARGET_TYPE(*original);
        BSLMA_CONSTRUCTIONUTIL_XLC_PLACEMENT_NEW_FIX;
    }
    else {
        // voidify(address) is used here to suppress compiler warning
        // "-Wclass-memaccess".
        memcpy(voidify(address), original, sizeof *original);
    }
}

template <class TARGET_TYPE, class ALLOCATOR>
inline
void
ConstructionUtil_Imp::destructiveMove(
                          TARGET_TYPE                               *address,
                          ALLOCATOR                                 *allocator,
                          bsl::integral_constant<int, e_NIL_TRAITS> *,
                          TARGET_TYPE                               *original)
{
    // TBD: should be ok with C++03 as well, but need to test edge cases first
#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES)
    ConstructionUtil::construct(address,
                                allocator,
                                bslmf::MovableRefUtil::move(*original));
#else
    ConstructionUtil::construct(address, allocator, *original);
#endif
    DestructionUtil::destroy(original);
}

#if defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)
// Suppress bde_verify warnings about return-by-value in this region.
// BDE_VERIFY pragma: push
// BDE_VERIFY pragma: -AR01: Type using allocator is returned by value

template <class TARGET_TYPE>
inline
TARGET_TYPE
ConstructionUtil_Imp::make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_BSLMA_ALLOCATOR_TRAITS> *)
{
    return TARGET_TYPE(allocator);
}

template <class TARGET_TYPE>
inline
TARGET_TYPE
ConstructionUtil_Imp::make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_ALLOCATOR_ARG_T_TRAITS> *)
{
    return TARGET_TYPE(bsl::allocator_arg, allocator);
}

template <class TARGET_TYPE>
inline
TARGET_TYPE
ConstructionUtil_Imp::make(bslma::Allocator                          *,
                           bsl::integral_constant<int, e_NIL_TRAITS> *)
{
    return TARGET_TYPE();
}

template <class TARGET_TYPE, class ANY_TYPE>
inline
TARGET_TYPE
ConstructionUtil_Imp::make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_BSLMA_ALLOCATOR_TRAITS> *,
         BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)                 argument)
{
    return TARGET_TYPE(BSLS_COMPILERFEATURES_FORWARD(ANY_TYPE, argument),
                       allocator);
}

template <class TARGET_TYPE, class ANY_TYPE>
inline
TARGET_TYPE
ConstructionUtil_Imp::make(
         bslma::Allocator                                           *allocator,
         bsl::integral_constant<int, e_USES_ALLOCATOR_ARG_T_TRAITS> *,
         BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)                 argument)
{
    return TARGET_TYPE(bsl::allocator_arg, allocator,
                       BSLS_COMPILERFEATURES_FORWARD(ANY_TYPE, argument));
}

template <class TARGET_TYPE, class ANY_TYPE>
inline
TARGET_TYPE
ConstructionUtil_Imp::make(
                         bslma::Allocator                            *,
                         bsl::integral_constant<int, e_NIL_TRAITS>   *,
                         BSLS_COMPILERFEATURES_FORWARD_REF(ANY_TYPE)  argument)
{
    return TARGET_TYPE(BSLS_COMPILERFEATURES_FORWARD(ANY_TYPE, argument));
}

// BDE_VERIFY pragma: pop
#endif // defined(BSLS_COMPILERFEATURES_GUARANTEED_COPY_ELISION)

template <class TARGET_TYPE>
inline
void *ConstructionUtil_Imp::voidify(TARGET_TYPE *address)
{
    return static_cast<void *>(
            const_cast<typename bsl::remove_cv<TARGET_TYPE>::type *>(address));
}

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

#endif // End C++11 code

#endif

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