// bsltf_allocemplacabletesttype.h                                    -*-C++-*-
#ifndef INCLUDED_BSLTF_ALLOCEMPLACABLETESTTYPE
#define INCLUDED_BSLTF_ALLOCEMPLACABLETESTTYPE

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

//@PURPOSE: Provide an allocating test class used to test 'emplace' methods.
//
//@CLASSES:
//  bsltf::AllocEmplacableTestType: allocating test class with 0..14 arguments
//
//@SEE_ALSO: bsltf_allocargumenttype, bsltf_templatetestfacility
//
//@DESCRIPTION: This component provides a (value-semantic) attribute class,
// 'bsltf::AllocEmplacableTestType', that is used to ensure that arguments are
// forwarded correctly to a type's constructor.  This component is similar to
// 'bsltf_emplacabletesttype', but provides a type that allocates on
// construction.
//
///Attributes
///----------
//..
//  Name     Type                           Default
//  -------  -----------------------------  -------
//  arg01    bsltf::AllocArgumentType< 1>   -1
//  arg02    bsltf::AllocArgumentType< 2>   -1
//  arg03    bsltf::AllocArgumentType< 3>   -1
//  arg04    bsltf::AllocArgumentType< 4>   -1
//  arg05    bsltf::AllocArgumentType< 5>   -1
//  arg06    bsltf::AllocArgumentType< 6>   -1
//  arg07    bsltf::AllocArgumentType< 7>   -1
//  arg08    bsltf::AllocArgumentType< 8>   -1
//  arg09    bsltf::AllocArgumentType< 9>   -1
//  arg10    bsltf::AllocArgumentType<10>   -1
//  arg11    bsltf::AllocArgumentType<11>   -1
//  arg12    bsltf::AllocArgumentType<12>   -1
//  arg13    bsltf::AllocArgumentType<13>   -1
//  arg14    bsltf::AllocArgumentType<14>   -1
//..
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Testing Methods With Argument Forwarding
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we will utilize 'bsltf::AllocEmplacableTestType' to
// test the implementation of a container's 'emplace' method.
//
// First, we create an elided definition of a container class, 'MyContainer',
// and show the signature of the 'emplace' method we intend to test:
//..
//  // container.h
//  // -----------
//  template <class TYPE>
//  class Container {
//      // This class template implements a value-semantic container type
//      // holding elements of the (template parameter) type 'TYPE'.  This
//      // class provides an 'emplace' method that constructs the element by
//      // forwarding a variable number of arguments to the 'TYPE' constructor.
//
//      // ...
//
//      // MANIPULATORS
//      template <class... Args>
//      void emplace(Args&&... arguments);
//          // Insert into this container a newly created 'TYPE' object,
//          // constructed by forwarding the specified (variable number of)
//          // 'arguments' to the corresponding constructor of 'TYPE'.
//
//      // ...
//  };
//..
// Then, we provide test machinery that will invoke the 'emplace' method with
// variable number of arguments:
//..
//  // container.t.cpp
//  // ---------------
//
//  template <class T>
//  bslmf::MovableRef<T> forwardCtorArg(T& argument, bsl::true_type);
//      // Return 'bslmf::MovableRef' to the specified 'argument'.
//
//  template <class T>
//  const T& forwardCtorArg(T& argument, bsl::false_type)
//      // Return a reference providing non-modifiable access to the
//      // specified 'argument'.
//
//  template <int N_ARGS, bool MOVE_ARG_01, bool MOVE_ARG_02>
//  void testCaseHelper()
//      // Call 'emplace' on the container and verify that value was correctly
//      // constructed and inserted into the container.  Forward (template
//      // parameter) 'N_ARGS' arguments to the 'emplace' method and ensure 1)
//      // that values are properly passed to the constructor of
//      // 'bsltf::AllocEmplacableTestType', 2) that the allocator is correctly
//      // configured for each argument in the newly inserted element in
//      // 'target', and 3) that the arguments are forwarded using copy
//      // ('false') or move semantics ('true') based on bool template
//      // parameters 'MOVE_ARG_01' ...  'MOVE_ARG_02'.
//  {
//      bslma::TestAllocator ta;
//..
// Here, we use 'AllocEmplacableTestType' as the contained type to ensure the
// arguments to the 'emplace' method are correctly forwarded to the contained
// type's constructor:
//..
//      Container<bsltf::AllocEmplacableTestType>        mX(&ta);
//      const Container<bsltf::AllocEmplacableTestType>& X = mX;
//
//      // Prepare the arguments
//      bslma::TestAllocator aa("args", veryVeryVeryVerbose);
//
//      bsltf::AllocArgumentType<1> A01(18, &aa);
//      bsltf::AllocArgumentType<2> A02(33, &aa);
//..
// Then, we call 'emplace' supplying test arguments, which should call the
// correct constructor of 'AllocEmplacableTestType' (which we will later
// verify):
//..
//      const bsl::integral_constant<bool, MOVE_ARG_01> MOVE_01 = {};
//      const bsl::integral_constant<bool, MOVE_ARG_02> MOVE_02 = {};
//      switch (N_ARGS) {
//        case 0: {
//          mX.emplace();
//        } break;
//        case 1: {
//          mX.emplace(forwardCtorArg(A01, MOVE_01));
//        } break;
//        case 2: {
//          mX.emplace(forwardCtorArg(A01, MOVE_01),
//                     forwardCtorArg(A02, MOVE_02));
//        } break;
//        default: {
//          assert(0);
//        } break;
//      }
//..
// We verify the correct arguments were forwarded to the
// 'AllocEmplcableTestType':
//..
//      // Verify that, depending on the corresponding template parameters,
//      // arguments were copied or moved.
//      assert(MOVE_ARG_01 == (bsltf::MoveState::e_MOVED == A01.movedFrom()));
//      assert(MOVE_ARG_02 == (bsltf::MoveState::e_MOVED == A02.movedFrom()));
//
//      // Verify that the element was constructed correctly.
//      const bsltf::AllocEmplacableTestType& V = X.front();
//
//      assert(18 == V.arg01() || N_ARGS < 1);
//      assert(33 == V.arg02() || N_ARGS < 2);
//  }
//..
// Finally, we call our templatized test case helper with a variety of template
// arguments:
//..
//  void testCase()
//  {
//      // Testing 'emplace' with 0 arguments.
//      testCaseHelper<0, false, false>();
//
//      // Testing 'emplace' with 1 argument.
//      testCaseHelper<1, false, false>();
//      testCaseHelper<1, true,  false>();
//
//      // Testing 'emplace' with 2 arguments.
//      testCaseHelper<2, false, false>();
//      testCaseHelper<2, true,  false>();
//      testCaseHelper<2, false, true >();
//      testCaseHelper<2, true,  true >();
//  }
//..

#include <bslscm_version.h>

#include <bslma_usesbslmaallocator.h>
#include <bsltf_allocargumenttype.h>

namespace BloombergLP {

namespace bslma { class Allocator; }

namespace bsltf {

                         // =============================
                         // class AllocEmplacableTestType
                         // =============================

class AllocEmplacableTestType {
    // This class provides a test object used to check that the arguments
    // passed for creating an object with an in-place representation are of the
    // correct types and values.
  public:
    // TYPEDEFS
    typedef bsltf::AllocArgumentType< 1> ArgType01;
    typedef bsltf::AllocArgumentType< 2> ArgType02;
    typedef bsltf::AllocArgumentType< 3> ArgType03;
    typedef bsltf::AllocArgumentType< 4> ArgType04;
    typedef bsltf::AllocArgumentType< 5> ArgType05;
    typedef bsltf::AllocArgumentType< 6> ArgType06;
    typedef bsltf::AllocArgumentType< 7> ArgType07;
    typedef bsltf::AllocArgumentType< 8> ArgType08;
    typedef bsltf::AllocArgumentType< 9> ArgType09;
    typedef bsltf::AllocArgumentType<10> ArgType10;
    typedef bsltf::AllocArgumentType<11> ArgType11;
    typedef bsltf::AllocArgumentType<12> ArgType12;
    typedef bsltf::AllocArgumentType<13> ArgType13;
    typedef bsltf::AllocArgumentType<14> ArgType14;

  private:
    // DATA
    ArgType01 d_arg01;
    ArgType02 d_arg02;
    ArgType03 d_arg03;
    ArgType04 d_arg04;
    ArgType05 d_arg05;
    ArgType06 d_arg06;
    ArgType07 d_arg07;
    ArgType08 d_arg08;
    ArgType09 d_arg09;
    ArgType10 d_arg10;
    ArgType11 d_arg11;
    ArgType12 d_arg12;
    ArgType13 d_arg13;
    ArgType14 d_arg14;

    // CLASS DATA
    static int s_numDeletes;
        // Track number of times the destructor is called.

  public:
    // CLASS METHODS
    static int getNumDeletes();
        // Return the number of times an object of this type has been
        // destroyed.

    // CREATORS
    AllocEmplacableTestType(bslma::Allocator *basicAllocator = 0);
    explicit AllocEmplacableTestType(ArgType01         arg01,
                                     bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            ArgType08         arg08,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            ArgType08         arg08,
                            ArgType09         arg09,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            ArgType08         arg08,
                            ArgType09         arg09,
                            ArgType10         arg10,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            ArgType08         arg08,
                            ArgType09         arg09,
                            ArgType10         arg10,
                            ArgType11         arg11,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            ArgType08         arg08,
                            ArgType09         arg09,
                            ArgType10         arg10,
                            ArgType11         arg11,
                            ArgType12         arg12,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            ArgType08         arg08,
                            ArgType09         arg09,
                            ArgType10         arg10,
                            ArgType11         arg11,
                            ArgType12         arg12,
                            ArgType13         arg13,
                            bslma::Allocator *basicAllocator = 0);
    AllocEmplacableTestType(ArgType01         arg01,
                            ArgType02         arg02,
                            ArgType03         arg03,
                            ArgType04         arg04,
                            ArgType05         arg05,
                            ArgType06         arg06,
                            ArgType07         arg07,
                            ArgType08         arg08,
                            ArgType09         arg09,
                            ArgType10         arg10,
                            ArgType11         arg11,
                            ArgType12         arg12,
                            ArgType13         arg13,
                            ArgType14         arg14,
                            bslma::Allocator *basicAllocator = 0);
        // Create an 'AllocEmplacableTestType' by initializing corresponding
        // attributes with the specified 'arg01'..'arg14', and initializing any
        // remaining attributes with their default value (-1).  Optionally
        // specify a 'basicAllocator' used to supply memory.  If
        // 'basicAllocator' is 0, the currently installed default allocator is
        // used.

    AllocEmplacableTestType(
                           const AllocEmplacableTestType&  original,
                           bslma::Allocator               *basicAllocator = 0);
        // Create an allocating, in-place test object having the same value as
        // the specified 'original'.  Optionally specify a 'basicAllocator'
        // used to supply memory.  If 'basicAllocator' is 0, the currently
        // installed default allocator is used.

    ~AllocEmplacableTestType();
        // Increment the count of calls to this destructor, and destroy this
        // object.

    // MANIPULATORS
#if BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L
    AllocEmplacableTestType& operator=(
                                 const AllocEmplacableTestType& rhs) = default;
        // Assign to this object the value of the specified 'rhs' object, and
        // return a reference providing modifiable access to this object.
#else
    //! AllocEmplacableTestType& operator=(
    //                           const AllocEmplacableTestType& rhs) = default;
#endif

    // ACCESSORS
    bslma::Allocator *allocator() const;
        // Return the allocator used to supply memory for this object.

    const ArgType01& arg01() const;
    const ArgType02& arg02() const;
    const ArgType03& arg03() const;
    const ArgType04& arg04() const;
    const ArgType05& arg05() const;
    const ArgType06& arg06() const;
    const ArgType07& arg07() const;
    const ArgType08& arg08() const;
    const ArgType09& arg09() const;
    const ArgType10& arg10() const;
    const ArgType11& arg11() const;
    const ArgType12& arg12() const;
    const ArgType13& arg13() const;
    const ArgType14& arg14() const;
        // Return the value of the correspondingly numbered argument that was
        // passed to the constructor of this object.

    bool isEqual(const AllocEmplacableTestType& rhs) const;
        // Return 'true' if the specified 'rhs' has the same value as this
        // object, and 'false' otherwise.  Two 'AllocEmplacableTestType'
        // objects have the same value if each of their corresponding
        // attributes have the same value.
};

// FREE OPERATORS
bool operator==(const AllocEmplacableTestType& lhs,
                const AllocEmplacableTestType& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' objects have the same
    // value, and 'false' otherwise.  Two 'AllocEmplacableTestType' objects
    // have the same value if each of their corresponding attributes have the
    // same value.

bool operator!=(const AllocEmplacableTestType& lhs,
                const AllocEmplacableTestType& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' objects do not have the
    // same value, and 'false' otherwise.  Two 'AllocEmplacableTestType'
    // objects do not have the same value if any of their corresponding
    // attributes do not have the same value.

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

                        // -----------------------------
                        // class AllocEmplacableTestType
                        // -----------------------------

// ACCESSORS
inline
const AllocEmplacableTestType::ArgType01&
AllocEmplacableTestType::arg01() const
{
    return d_arg01;
}

inline
const AllocEmplacableTestType::ArgType02&
AllocEmplacableTestType::arg02() const
{
    return d_arg02;
}

inline
const AllocEmplacableTestType::ArgType03&
AllocEmplacableTestType::arg03() const
{
    return d_arg03;
}

inline
const AllocEmplacableTestType::ArgType04&
AllocEmplacableTestType::arg04() const
{
    return d_arg04;
}

inline
const AllocEmplacableTestType::ArgType05&
AllocEmplacableTestType::arg05() const
{
    return d_arg05;
}

inline
const AllocEmplacableTestType::ArgType06&
AllocEmplacableTestType::arg06() const
{
    return d_arg06;
}

inline
const AllocEmplacableTestType::ArgType07&
AllocEmplacableTestType::arg07() const
{
    return d_arg07;
}

inline
const AllocEmplacableTestType::ArgType08&
AllocEmplacableTestType::arg08() const
{
    return d_arg08;
}

inline
const AllocEmplacableTestType::ArgType09&
AllocEmplacableTestType::arg09() const
{
    return d_arg09;
}

inline
const AllocEmplacableTestType::ArgType10&
AllocEmplacableTestType::arg10() const
{
    return d_arg10;
}

inline
const AllocEmplacableTestType::ArgType11&
AllocEmplacableTestType::arg11() const
{
    return d_arg11;
}

inline
const AllocEmplacableTestType::ArgType12&
AllocEmplacableTestType::arg12() const
{
    return d_arg12;
}

inline
const AllocEmplacableTestType::ArgType13&
AllocEmplacableTestType::arg13() const
{
    return d_arg13;
}

inline
const AllocEmplacableTestType::ArgType14&
AllocEmplacableTestType::arg14() const
{
    return d_arg14;
}

inline
bslma::Allocator *AllocEmplacableTestType::allocator() const
{
    return d_arg01.allocator();
}

inline
bool AllocEmplacableTestType::isEqual(const AllocEmplacableTestType& rhs) const
{
    return d_arg01 == rhs.d_arg01
        && d_arg02 == rhs.d_arg02
        && d_arg03 == rhs.d_arg03
        && d_arg04 == rhs.d_arg04
        && d_arg05 == rhs.d_arg05
        && d_arg06 == rhs.d_arg06
        && d_arg07 == rhs.d_arg07
        && d_arg08 == rhs.d_arg08
        && d_arg09 == rhs.d_arg09
        && d_arg10 == rhs.d_arg10
        && d_arg11 == rhs.d_arg11
        && d_arg12 == rhs.d_arg12
        && d_arg13 == rhs.d_arg13
        && d_arg14 == rhs.d_arg14;
}

// FREE OPERATORS
inline
bool operator==(const bsltf::AllocEmplacableTestType& lhs,
                const bsltf::AllocEmplacableTestType& rhs)
{
    return lhs.isEqual(rhs);
}

inline
bool operator!=(const bsltf::AllocEmplacableTestType& lhs,
                const bsltf::AllocEmplacableTestType& rhs)
{
    return !lhs.isEqual(rhs);
}

}  // close package namespace

// TRAITS
namespace bslma {
template <>
struct UsesBslmaAllocator<bsltf::AllocEmplacableTestType> : bsl::true_type
{
};

}  // close namespace bslma

}  // close enterprise namespace

#endif

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