// bsltf_templatetestfacility.h                                       -*-C++-*-
#ifndef INCLUDED_BSLTF_TEMPLATETESTFACILITY
#define INCLUDED_BSLTF_TEMPLATETESTFACILITY

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

//@PURPOSE: Provide utilities to help with testing templates.
//
//@CLASSES:
//  bsltf::TemplateTestFacility: namespace for template-testing utilities
//
//@MACROS:
//  BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE(CLASS, METHOD, TYPE...): run all
//  BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_PRIMITIVE: list of primitive types
//  BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_USER_DEFINED: list user types
//  BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_REGULAR: list of typical types
//  BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_AWKWARD: list of atypical types
//  BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_ALL: list all `bslmf` types
//
//@SEE_ALSO: bsltf_simpletesttype, bslstl_map
//
//@DESCRIPTION: When testing a container template having a type parameter, we
// need to ensure that the template supports its contractually specified
// categories of parameter types.  The `bsltf` package provides a
// representative set of types intended for testing that can be used as
// template parameters for doing this kind of verification.
//
// Creating a separate test for each category of types supported by a template
// would be cumbersome.  Instead, writing a single templatized test is usually
// preferable.  Unfortunately, different types often require different syntaxes
// for constructing an object and getting an object's value.  This
// inconsistency makes writing generic code rather difficult.
//
// This component provides a solution with a utility `struct`,
// `TemplateTestFacility`, that defines two class method templates, `create`
// and `getIdentifier`, that respectively have consistent syntaxes for creating
// objects and getting a integer value representing the state of objects of a
// parameterized type.
//
// This component also provides a macro,
// `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE`, that serves as a convenient way
// to instantiate and invoke a template (for testing) having a type parameter
// for a specified list of types.  In addition, this component provides a set
// of macros referring to commonly useful lists of types intended for testing
// that can be used as arguments to `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE`.
//
// The utilities and macros provided by this component, along with the types
// defined in the `bsltf` package, are explained in more detail in the
// following sections.
//
///`TemplateTestFacility`
///----------------------
// The `TemplateTestFacility` `struct` provides the following static (class)
// method templates to construct objects and get the states of objects of a
// supported parameterized type (supported types are those types intended for
// testing defined in the `bsltf` package):
//
// * `create`:    Return an object of the parameterized `TYPE` whose value is
//                uniquely associated with a specified integer identifier.
//
// * `getIdentifier`: Return the integer identifier used to create a specified
//                    object of the parameterized `TYPE`.
//
///Macros and Test Types
///---------------------
// The `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` macro instantiates a
// specified class template for a specified list of types and call a specified
// class method of each instantiation.  The macro takes in arguments in the
// following order:
//
// * The name of the class template to be instantiated
// * The name of the class method to be invoked
// * The names of the types for which the class template will be instantiated
//   (up to 20)
//
// This component also defines a set of macros, each providing a list of types,
// that can be used as the last argument to
// `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE`.  The following is a brief
// synopsis of these macros (note that all macros names have the
// `BSLTF_TEMPLATETESTFACILITY_` prefix, which is omitted for layout
// efficiency):
//
// * `TEST_TYPES_PRIMITIVE`:     list of primitive types
// * `TEST_TYPES_USER_DEFINED`:  list of user-defined types
// * `TEST_TYPES_REGULAR`:       list of typically used types
// * `TEST_TYPES_AWKWARD`:       list of types with odd behaviors
// * `TEST_TYPES_ALL`:           list of all of the types
//
// The `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_PRIMITIVE` macro refers to a
// representative set of primitive types that are useful for testing:
// ```
// Type                                Description
// ----                                -----------
// signed char                         signed character
//
// size_t                              signed integral type
//
// TemplateTestFacility::ObjectPtr     pointer to an object
//
// TemplateTestFacility::FunctionPtr   pointer to a function
//
// TemplateTestFacility::MethodPtr     pointer to a method
// ```
// The `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_USER_DEFINED` macro refers to a
// representative set of user-defined types that are useful for testing (note
// that all types described here belong to the `bsltf` namespace, which is not
// explicitly qualified for layout efficiency):
// ```
// Type                                Description
// ----                                -----------
// EnumeratedTestType::Enum            an enumeration
//
// UnionTestType                       a union
//
// SimpleTestType                      class with no special traits defined
//
// AllocTestType                       class that allocates memory, defines
//                                     the 'bslma::UsesBslmaAllocator'
//                                     trait, and ensures it is not bitwise
//                                     moved
//
// NonOptionalAllocTestType            class that allocates memory, defines
//                                     the 'bslma::UsesBslmaAllocator'
//                                     trait, ensures it is not bitwise
//                                     moved, and does not have default ctor.
//
// MovableTestType                     class that has both move and copy
//                                     semantics, and ensures it is not
//                                     bitwise moved
//
// MovableAllocTestType                class that has both move and copy
//                                     semantics, allocates memory, defines
//                                     the 'bslma::UsesBslmaAllocator'
//                                     trait, and ensures it is not bitwise
//                                     moved
//
// MoveOnlyAllocTestType               class that has only move semantics,
//                                     allocates memory, defines the
//                                     'bslma::UsesBslmaAllocator'
//                                     trait, and ensures it is not bitwise
//                                     moved
//
// BitwiseCopyableTestType             class that is bitwise-copyable and
//                                     defines the
//                                     'bsl::is_trivially_copyable'
//                                     trait
//
// BitwiseMoveableTestType             class that is bitwise-moveable and
//                                     defines the
//                                     'bslmf::IsBitwiseMoveable'
//                                     trait
//
// AllocatingBitwiseMoveableTestType   class that allocates memory, is
//                                     bitwisemoveable, and defines the
//                                     'bslma::UsesBslmaAllocator'
//                                     and 'bslmf::IsBitwiseMoveable'
//                                     traits
//
// NonTypicalOverloadsTestType         class that defines and assert on
//                                     invocation of certain
//                                     non-typically-overloaded operators
//                                     ('operator new', 'operator delete',
//                                     'operator&') to ensure that they are
//                                     not called
//
// EmplacableTestType                  class that takes <= 14 non-allocating
//                                     arguments and is used to ensure that
//                                     arguments are forwarded correctly
//                                     from functions and methods taking
//                                     variable number of arguments and their
//                                     analagous in C++03 environments.
//
// AllocEmplacableTestType             class that takes up to 14 allocating
//                                     arguments and is used to ensure that
//                                     arguments are forwarded correctly
//                                     from functions and methods taking
//                                     variable number of arguments and their
//                                     analagous in C++03 environments.
// ```
//
// The `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_REGULAR` macro refers to the
// union of the types provided by
// `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_PRIMITIVE` and
// `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_USER_DEFINED`.  These types are
// designed to work within the regular operating conditions of a typical
// template.  Typically, a test driver for a template instantiates its tests
// (using the `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` macro) for all of the
// types referred by `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_REGULAR`.
//
// The `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_AWKWARD` macro refers to a set of
// types that have certain attributes that make them unlikely to work for all
// of the operations of a template.  Typically, not all methods of a template
// are instantiable with these types, so these types are most often used
// independently in tests explicitly designed for a (single) type.
// ```
// Type                                Description
// ----                                -----------
// NonAssignableTestType               class having no assignment operator
//
// NonCopyConstructibleTestType        class having no copy constructor (Note
//                                     that this class can not be created with
//                                     'TemplateTestFacility::create' because
//                                     the class method returns the newly
//                                     constructed object by value.)
//
// NonDefaultConstructibleTestType     class having no default constructor
//
// NonEqualComparableTestType          class having no equality-comparison
//                                     operators
// ```
// The `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_ALL` refers to all the test types
// provided in the `bsltf` package.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Using the `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` Macro
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we demonstrate how to use
// `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` to call a class method of a
// template for a list of types.
//
// First, we define a `struct` template `TestTemplate` taking in a
// parameterized `TYPE` that has a class method, `printTypeName`:
// ```
// template <class TYPE>
// struct TestTemplate {
//     // This 'struct' provides a namespace for a simple test method.
//
//     // CLASS METHODS
//     static void printTypeName();
//         // Prints the name of the parameterized 'TYPE' to the console.
// };
//
// template <>
// void TestTemplate<int>::printTypeName()
// {
//     printf("int\n");
// }
//
// template <>
// void TestTemplate<char>::printTypeName()
// {
//     printf("char\n");
// }
//
// template <>
// void TestTemplate<double>::printTypeName()
// {
//     printf("double\n");
// }
// ```
// Now, we can instantiate the `TestTemplate` class for each of the types
// `int`, `char`, and `double`, and call the `printTypeName` class method of
// each instantiation using the `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE`
// macro:
// ```
// BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE(TestTemplate,
//                                          printTypeName,
//                                          int, char, double);
// ```
// Finally, we observe the console output:
// ```
// int
// char
// double
// ```
//
///Example 2: Writing a Type Independent Test Driver
///- - - - - - - - - - - - - - - - - - - - - - - - -
// In this example, we demonstrate using the `TemplateTestFacility` `struct`
// and the macros provided by this component to test the default constructor
// and primary manipulator of a class template in the context of a typical
// BDE-style test driver.  Note that a goal of the demonstrated test is to
// validate the class template with a broad range of types emulating those with
// which the template might be instantiated.
//
// First, we define a simple class template, `MyNullableValue`, that we will
// later need to test:
// ```
// template <class TYPE>
// class MyNullableValue {
//     // This (value-semantic) class template extends the parameterized
//     // 'TYPE' to include the notion of a "null" value.
//
//     // DATA
//     TYPE d_value;     // non-null value
//     bool d_nullFlag;  // flag to indicate if the value is null
//
//   public:
//     MyNullableValue()
//         // Create a 'MyNullableValue' that initially has a value of null.
//     : d_nullFlag(true)
//     {
//     }
//
//     bool isNull() const
//         // Return 'true' if this object is null, and 'false' otherwise.
//     {
//         return d_nullFlag;
//     }
//
//     void makeNull()
//         // Set this object to the null value.
//     {
//         d_nullFlag = true;
//     }
//
//     const TYPE& value() const {
//         // Return a reference providing non-modifiable access to the
//         // underlying object of the parameterized 'TYPE'.  The behavior is
//         // undefined if the object is null.
//         return d_value;
//     }
//
//     void makeValue(const TYPE& value)
//         // Set the value of this object to be that of the specified 'value'
//         // of the parameterized 'TYPE'.
//     {
//         d_nullFlag = false;
//         d_value = value;
//     }
// };
// ```
// Then, we define some aliases for the micros that will be used by the test
// driver:
// ```
// #define RUN_EACH_TYPE BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE
// #define TEST_TYPES_REGULAR BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_REGULAR
// ```
// Next, we define a `struct` template, `MyTestDriver`, that provides a
// namespace containing the test cases (here, only `testCase2` is defined for
// brevity) of the test driver:
// ```
// template <class TYPE>
// struct MyTestDriver {
//     // This 'struct' provides a namespace for the class methods used to
//     // implement the test driver.
//
//     // TYPES
//     typedef MyNullableValue<TYPE> Obj;
//         // This 'typedef' provides an alias to the type under testing.
//
//     static void testCase2();
//         // Test primary manipulators.
// };
// ```
// Now, we define the implementation of `MyTestDriver::testCase2`:
// ```
// template <class TYPE>
// void MyTestDriver<TYPE>::testCase2()
// {
//     // --------------------------------------------------------------------
//     // DEFAULT CTOR, PRIMARY MANIPULATORS, AND DTOR
//     //   Ensure that we can use the default constructor to create an
//     //   object (having the default-constructed value), use the primary
//     //   manipulators to put that object into any state relevant for
//     //   thorough testing, and use the destructor to destroy it safely.
//     //
//     // Concerns:
//     //: 1 An object created using the default constructor (with or without
//     //:   a supplied allocator) has the contractually specified value.
//     //:
//     //: 2 The 'makeValue' method sets the value of a object to any
//     //:   specified value.
//     //:
//     //: 3 The 'makeNull' method set the value of a object to null.
//     //:
//     //: 4 Objects of different values can coexist.
//     //:
//     //: 5 The destructor does not modify other objects.
//     //
//     // Plan:
//     //: 1 Default-construct an object and use the (as yet unproven) salient
//     //:   attribute accessors to verify that the value of the object is the
//     //:   null value.  (C-1)
//     //:
//     //: 2 Default-construct another object, and use the 'makeValue' method,
//     //:   to set the value of the object to a non-null value.  Use the (as
//     //:   yet unproven) salient attribute accessors to verify that the new
//     //:   object has the expected value and the object created in P-1 still
//     //:   has the same value.  (C-2, 4)
//     //:
//     //: 3 Using the loop-based approach, for each identifier in a range of
//     //:   integer identifiers:
//     //:
//     //:   1 Default-construct a modifiable object, 'mL', and use the (as
//     //:     yet unproven) salient attribute accessors to verify the value
//     //:     of the default constructed object is the null value.  (C-1)
//     //:
//     //:   2 Create an object of the parameterized 'TYPE', 'LV', using the
//     //:     'TemplateTestFacility::create' class method template,
//     //:     specifying the integer loop identifier.
//     //:
//     //:   3 Use the 'makeValue' method to set the value of 'mL' to 'LV'.
//     //:     Use the (as yet unproven) salient attribute accessors to verify
//     //:     'mL' has the expected value.  (C-2)
//     //:
//     //:   4 Invoke the 'makeNull' method of 'mL'.  Use the attribute
//     //:     accessors to verify the value of the object is now null.  (C-3)
//     //:
//     //: 4 Create an object in a nested block.  Below the block, verify the
//     //:   objects created in P-1 and P-2 still have the same value.  (C-5)
//     //
//     // Testing:
//     //   MyNullableValue();
//     //   ~MyNullableValue();
//     //   void makeNull();
//     //   void MakeValue(const TYPE& value);
//     // --------------------------------------------------------------------
//
//     if (verbose)
//                 printf("\nDEFAULT CTOR, PRIMARY MANIPULATORS, AND DTOR"
//                        "\n============================================\n");
//
//
//     if (verbose) printf("\nTesting default constructor.\n");
//
//     Obj mW; const Obj& W = mW;
//     assert(true == W.isNull());
//
//     Obj mX; const Obj& X = mX;
//     const TYPE XV = TemplateTestFacility::create<TYPE>(1);
//     mX.makeValue(XV);
//     assert(1 == TemplateTestFacility::getIdentifier<TYPE>(X.value()));
//
//     if (verbose) printf("\nTesting primary manipulators.\n");
//
//     for (size_t ti = 0; ti < 10; ++ti) {
//
//         if (veryVerbose) { T_ P(ti) }
//
//         Obj mL; const Obj& L = mL;
//         assert(true == L.isNull());
//
//         const TYPE LV = TemplateTestFacility::create<TYPE>(ti);
//
//         mL.makeValue(LV);
//         assert(false == L.isNull());
//         assert(LV == L.value());
//
//         mL.makeNull();
//         assert(true == L.isNull());
//     }
//
//     if (verbose) printf("\nTesting destructor.\n");
//     {
//         Obj Z;
//     }
//
//     assert(true == W.isNull());
//     assert(XV == X.value());
// }
// ```
// Notice that, we create objects of the parameterized `TYPE` using the
// `TemplateTestFacility::create` class method template specifying an integer
// identifier; the created object has a value that is uniquely associated with
// the integer identifier.
//
// Also notice that we verified that an object of the parameterized `TYPE` has
// the expected value in two ways:
//
// 1. By equal comparing (1) the integer identifier returned from calling the
//    `TemplateTestFacility::getIdentifier` class method template (specifying
//    the object), and (2) the integer identifier uniquely associated with the
//    expected state of the object.
// 2. By directly using the equality-comparison operator for the parameterized
//    `TYPE`.  Note that the equality-comparison operator is defined for all
//    types intended for testing in the `bsltf` package except for
//    `bsltf::NonEqualComparableTestType`.
//
// Finally, we use the `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` macro to
// instantiate `MyTestDriver` for each of the types listed in
// `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_REGULAR` and invoke the `testCase2`
// class method of each instantiation:
// ```
// case 2: {
//   // ----------------------------------------------------------------------
//   // DEFAULT CTOR & PRIMARY MANIPULATORS
//   // ----------------------------------------------------------------------
//
//   if (verbose) printf("\nDEFAULT CTOR & PRIMARY MANIPULATORS"
//                       "\n===================================\n");
//
//   RUN_EACH_TYPE(MyTestDriver, testCase2, TEST_TYPES_REGULAR);
// } break;
// ```

#include <bslscm_version.h>

#include <bsltf_allocbitwisemoveabletesttype.h>
#include <bsltf_allocemplacabletesttype.h>
#include <bsltf_alloctesttype.h>
#include <bsltf_bitwisecopyabletesttype.h>
#include <bsltf_bitwisemoveabletesttype.h>
#include <bsltf_emplacabletesttype.h>
#include <bsltf_enumeratedtesttype.h>
#include <bsltf_movablealloctesttype.h>
#include <bsltf_movabletesttype.h>
#include <bsltf_moveonlyalloctesttype.h>
#include <bsltf_movestate.h>
#include <bsltf_nonassignabletesttype.h>
#include <bsltf_noncopyconstructibletesttype.h>
#include <bsltf_nondefaultconstructibletesttype.h>
#include <bsltf_nonequalcomparabletesttype.h>
#include <bsltf_nonoptionalalloctesttype.h>
#include <bsltf_nontypicaloverloadstesttype.h>
#include <bsltf_simpletesttype.h>
#include <bsltf_stdalloctesttype.h>
#include <bsltf_uniontesttype.h>
#include <bsltf_wellbehavedmoveonlyalloctesttype.h>

#include <bslma_allocatortraits.h>
#include <bslma_destructorguard.h>
#include <bslma_mallocfreeallocator.h>
#include <bslma_bslallocator.h>

#include <bslmf_assert.h>
#include <bslmf_movableref.h>

#include <bsls_assert.h>
#include <bsls_objectbuffer.h>
#include <bsls_types.h>
#include <bsls_util.h>

#include <stddef.h>  // for 'size_t'
#include <stdio.h>  // for 'printf'

#include <stdlib.h>  // for 'atoi'

namespace BloombergLP {
namespace bsltf {

                        // ====================================
                        // class TemplateTestFacility_StubClass
                        // ====================================

/// This class provides a single method template, `method`, that simply
/// returns the parameterized integer `IDENTIFIER`.  Note that the purpose
/// of this class is to serve as a stub class and method to be referred by
/// `TemplateTestFacility::ObjectPtr` and `TemplateTestFacility::MethodPtr`
/// respectively.
class TemplateTestFacility_StubClass {

  public:
    // MANIPULATORS

    /// Return the parameterized `IDENTIFIER`.
    template <int IDENTIFIER>
    int method();
};

                        // ========================================
                        // class TemplateTestFacility_CompareHelper
                        // ========================================

class TemplateTestFacility_CompareHelper {
  public:
    // CLASS METHODS
    template <class TYPE>
    static bool areEqual(const TYPE& lhs, const TYPE& rhs);

    static bool areEqual(const NonEqualComparableTestType& lhs,
                         const NonEqualComparableTestType& rhs);

    template <class TYPE>
    static bool areNotEqual(const TYPE& lhs, const TYPE& rhs);

    static bool areNotEqual(const NonEqualComparableTestType& lhs,
                            const NonEqualComparableTestType& rhs);
};

                        // ===========================
                        // struct TemplateTestFacility
                        // ===========================

/// This `struct` provides a namespace that contains three aliases for types
/// intended to be used as template parameters for testing templates.  The
/// namespace also contain two class method templates, `create` and
/// `getIdentifier`, that respectively provides a consistent interface to
/// (1) create a specified object of a parameterized type from an integer
/// identifier and (2) get the identifier value of a specified object.  The
/// identifier value returned from the `getIdentifier` method is undefined
/// unless the specified object was originally created with the `create`
/// class method template.
struct TemplateTestFacility {

  private:
    /// Return a pointer to a null-terminated string that will parse as
    /// having the same value as the specified `identifier`.  The behavior
    /// is undefined unless `0 <= identifier < 128`.
    static const char* nullTerminatedStringForIdentifier(int identifier);

  public:
    // PUBLIC TYPES

    /// This `typedef` is an alias for a pointer to a
    /// `TemplateTestFacility_StubClass` object.
    typedef TemplateTestFacility_StubClass *ObjectPtr;

    /// This `typedef` is an alias for a pointer to a function pointer.
    typedef void (*FunctionPtr) ();

    /// This `typedef` is an alias for a pointer to a method of
    /// `TemplateTestFacility_StubClass` taking no arguments and returning
    /// an `int`.
    typedef int (TemplateTestFacility_StubClass::*MethodPtr) ();

    // CLASS METHODS

    /// Return a new object of the parameterized `TYPE` whose state is
    /// unique for the specified `identifier`.  The behavior is undefined
    /// unless `0 <= value < 128` and `TYPE` is contained in the macro
    /// `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_ALL`.
    template <class TYPE>
    static TYPE create(int identifier);

    /// Create an object of the parameterized `TYPE` at the specified
    /// `address` whose state is unique for the specified `identifier`.  The
    /// behavior is undefined unless `0 <= identifier < 128` and `TYPE` is
    /// contained in the macro `BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_ALL`.
    template <class TYPE, class ALLOCATOR>
    static void emplace(TYPE *address, int identifier, ALLOCATOR allocator);
    template <class TYPE, class ALLOCATOR>
    static void emplace(TYPE *address, int identifier, ALLOCATOR *allocator);

    /// Create a pointer to the parameterized `TYPE` at the specified
    /// `address` whose value is unique for the specified `identifier`.  The
    /// behavior is undefined unless `0 <= identifier < 128`.  Note that no
    /// object is created at the address of the returned pointer, nor is it
    /// guaranteed to be a valid address for an object (or function).  Also
    /// note that the same address may be returned for different allocators,
    /// and is guaranteed to be unique only with respect to the `identifier`
    /// value.
    template <class TYPE, class ALLOCATOR>
    static void emplace(TYPE **address, int identifier, ALLOCATOR allocator);
    template <class TYPE, class ALLOCATOR>
    static void emplace(TYPE **address, int identifier, ALLOCATOR *allocator);

    /// Create at the specified `address` a pointer to a null-terminated
    /// string that will parse as having the same value as the specified
    /// `identifier`.  The specified `allocator` is not used.  The behavior
    /// is undefined unless `0 <= identifier < 128`.
    template <class ALLOCATOR>
    static void
    emplace(const char **address, int identifier, ALLOCATOR allocator);
    template <class ALLOCATOR>
    static void
    emplace(const char **address, int identifier, ALLOCATOR *allocator);

    template <class ALLOCATOR>
    static void emplace(char *address, int identifier, ALLOCATOR allocator);
    template <class ALLOCATOR>
    static void
    emplace(char *address, int identifier, ALLOCATOR *allocator);
    template <class ALLOCATOR>
    static void
    emplace(signed char *address, int identifier, ALLOCATOR allocator);
    template <class ALLOCATOR>
    static void
    emplace(signed char *address, int identifier, ALLOCATOR *allocator);
    template <class ALLOCATOR>
    static void
    emplace(unsigned char *address, int identifier, ALLOCATOR allocator);
    template <class ALLOCATOR>
    static void
    emplace(unsigned char *address, int identifier, ALLOCATOR *allocator);

    /// Set the character object at the specified `address` to the value of
    /// the specified `identifier`.  The specified `allocator` is not used.
    /// The behavior is undefined unless `0 <= identifier < 128`.  Note that
    /// these overloads are needed only to avoid narrowing conversion
    /// warnings that will occur in lower-level utilities when using this
    /// test facility.
    template <class ALLOCATOR>

    static void
    emplace(EmplacableTestType *address, int identifier, ALLOCATOR allocator);
    template <class ALLOCATOR>
    static void
    emplace(EmplacableTestType *address, int identifier, ALLOCATOR *allocator);

    template <class ALLOCATOR>
    static void
    emplace(AllocEmplacableTestType *address,
            int                      identifier,
            ALLOCATOR                allocator);
    template <class ALLOCATOR>
    static void
    emplace(AllocEmplacableTestType *address,
            int                      identifier,
            ALLOCATOR               *allocator);

    /// Set the enumeration at the specified `address` to the value of the
    /// specified `identifier`.  The specified `allocator` is not used.  The
    /// behavior is undefined unless `0 <= identifier < 128`.
    template <class ALLOCATOR>
    static void emplace(EnumeratedTestType::Enum *address,
                        int                       identifier,
                        ALLOCATOR                 allocator);
    template <class ALLOCATOR>
    static void emplace(EnumeratedTestType::Enum *address,
                        int                       identifier,
                        ALLOCATOR                *allocator);

    /// Set the pointer-to-method at the specified `address` to the value of
    /// the specified `identifier`.  The specified `allocator` is not used.
    /// The behavior is undefined unless `0 <= identifier < 128`.
    template <class ALLOCATOR>
    static void
    emplace(MethodPtr *address, int identifier, ALLOCATOR allocator);
    template <class ALLOCATOR>
    static void
    emplace(MethodPtr *address, int identifier, ALLOCATOR *allocator);

    /// Return the integer identifier that uniquely identifies the specified
    /// `object`.  The behavior is undefined unless `object` could be
    /// created from the `TemplateTestFacility::create` class method
    /// template.
    template <class TYPE>
    static int getIdentifier(const TYPE& object);

    /// Return the integer identifier that uniquely identifies the specified
    /// `object`.  The behavior is undefined unless `object` was created by
    /// a call to the `TemplateTestFacility::create` class method template,
    /// or is a copy of such an object.
    template <class TYPE>
    static int getIdentifier(TYPE*const& object);

    /// Return the integer identifier that uniquely identifies the specified
    /// `object`.  The behavior is undefined unless `object` could be
    /// created from the `TemplateTestFacility::create` class method
    /// template.
    static int getIdentifier(const char*const& object);

    /// Return the integer identifier that uniquely identifies the specified
    /// `object`.  The behavior is undefined unless `object` could be
    /// created from the `TemplateTestFacility::create` class method
    /// template.
    template <class ALLOC>
    static int getIdentifier(const StdAllocTestType<ALLOC>& object);

    /// Return the moved-from state of the specified `object, or `e_UNKNOWN'
    /// if (template parameter) `TYPE` does not support such a query.
    template <class TYPE>
    static bsltf::MoveState::Enum getMovedFromState(const TYPE& object);

    /// Return the moved-into state of the specified `object, or `e_UNKNOWN'
    /// if (template parameter) `TYPE` does not support such a query.
    template <class TYPE>
    static bsltf::MoveState::Enum getMovedIntoState(const TYPE& object);

    /// Set the moved-into state of the specified 'object to the specified
    /// `value` if (template parameter) `TYPE` does supports move states.
    template <class TYPE>
    static void setMovedIntoState(TYPE *object, bsltf::MoveState::Enum value);
};

// FREE FUNCTIONS

/// Print the value of the specified `obj` to the console.  Note that this
/// free function is provided to allow `bsls_bsltestutil` to support these
/// types intended for testing.  See the component-level documentation for
/// `bsls_bsltestutil` for more details.
void debugprint(const AllocTestType& obj);
void debugprint(const NonOptionalAllocTestType& obj);
void debugprint(const AllocBitwiseMoveableTestType& obj);
void debugprint(const AllocEmplacableTestType& obj);
void debugprint(const BitwiseCopyableTestType& obj);
void debugprint(const BitwiseMoveableTestType& obj);
void debugprint(const EmplacableTestType& obj);
void debugprint(const EnumeratedTestType::Enum& obj);
void debugprint(const MovableAllocTestType& obj);
void debugprint(const MovableTestType& obj);
void debugprint(const MoveOnlyAllocTestType& obj);
void debugprint(const NonTypicalOverloadsTestType& obj);
void debugprint(const NonAssignableTestType& obj);
void debugprint(const NonCopyConstructibleTestType& obj);
void debugprint(const NonDefaultConstructibleTestType& obj);
void debugprint(const NonEqualComparableTestType& obj);
void debugprint(const SimpleTestType& obj);
template <class ALLOC> void debugprint(const StdAllocTestType<ALLOC>& obj);
void debugprint(const UnionTestType& obj);
void debugprint(const WellBehavedMoveOnlyAllocTestType& obj);

                       // =================
                       // Macro Definitions
                       // =================

/// This macro refers to all of the primitive test types defined in this
/// package.  Note that it can be used as the last argument to the
/// `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` macro.
#define BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_PRIMITIVE                       \
        signed char,                                                          \
        size_t,                                                               \
        const char *,                                                         \
        bsltf::TemplateTestFacility::ObjectPtr,                               \
        bsltf::TemplateTestFacility::FunctionPtr,                             \
        bsltf::TemplateTestFacility::MethodPtr

/// This macro refers to all of the user-defined test types defined in this
/// package.  Note that the macro can be used as the last argument to the
/// `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` macro.
#define BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_USER_DEFINED                    \
    bsltf::EnumeratedTestType::Enum,                                          \
    bsltf::UnionTestType,                                                     \
    bsltf::SimpleTestType,                                                    \
    bsltf::AllocTestType,                                                     \
    bsltf::BitwiseCopyableTestType,                                           \
    bsltf::BitwiseMoveableTestType,                                           \
    bsltf::AllocBitwiseMoveableTestType,                                      \
    bsltf::MovableTestType,                                                   \
    bsltf::MovableAllocTestType,                                              \
    bsltf::NonTypicalOverloadsTestType

/// This macro refers to all of the regular test types defined in this
/// package.  Note that the macro can be used as the last argument to the
/// `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` macro.
#define BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_REGULAR                         \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_PRIMITIVE,                      \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_USER_DEFINED

#define BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_AWKWARD                         \
        bsltf::NonAssignableTestType,                                         \
        bsltf::NonDefaultConstructibleTestType,                               \
        bsltf::NonEqualComparableTestType
        // TBD: move-only types should be in a separate movable macro, as many
        //      existing test rely on copying.
        //  bsltf::MoveOnlyAllocTestType
        // TBD: cannot add following as they support only 14 valid values, and
        //      'create'/'getIdentifier' require support for (at least) 128
        //      distinct values.  'bool' has the same issue, as do empty types.
        //  bsltf::AllocEmplacableTestType
        //  bsltf::EmplacableTestType
    // This macro refers to all of the awkward test types defined in this
    // package.  Note that the macro can be used as the last argument to the
    // 'BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE' macro.

/// This macro refers to all of the test types defined in this package.
/// Note that the macro can be used as the last argument to the
/// `BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE` macro.
#define BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_ALL                             \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_REGULAR,                        \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_AWKWARD


#define BSLTF_TEMPLATETESTFACILITY_NUM_ARGS_IMPL(X20, X19, X18, X17, X16,     \
                                                 X15, X14, X13, X12, X11,     \
                                                 X10,  X9,  X8,  X7,  X6,     \
                                                  X5,  X4,  X3,  X2,  X1,     \
                                                   N, ...)                    \
        N

// The 'BSLTF_TEMPLATETESTFACILITY_EXPAND' macro is required to workaround a
// pre-processor issue on windows that prevents __VA_ARGS__ to be expanded in
// the definition of some macros.
#define BSLTF_TEMPLATETESTFACILITY_EXPAND(X)                                  \
        X

#define BSLTF_TEMPLATETESTFACILITY_NUM_ARGS(...)                              \
        BSLTF_TEMPLATETESTFACILITY_EXPAND(                                    \
        BSLTF_TEMPLATETESTFACILITY_NUM_ARGS_IMPL(__VA_ARGS__,                 \
                                                 20, 19, 18, 17, 16, 15, 14,  \
                                                 13, 12, 11, 10,  9,  8,  7,  \
                                                 6, 5, 4, 3, 2, 1, 0))

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL1(C, M, T1)              \
        C<T1>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL2(C, M, T1, T2)          \
        C<T1>::M(); C<T2>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL3(C, M, T1, T2, T3)      \
        C<T1>::M(); C<T2>::M(); C<T3>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL4(C, M, T1, T2, T3, T4)  \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL5(C, M, T1, T2, T3, T4,  \
                                                       T5)                    \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL6(C, M, T1, T2, T3, T4,  \
                                                       T5, T6)                \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL7(C, M, T1, T2, T3, T4,  \
                                                       T5, T6, T7)            \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL8(C, M, T1, T2, T3, T4,  \
                                                       T5, T6, T7, T8)        \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL9(C, M, T1, T2, T3, T4,  \
                                                       T5, T6, T7, T8, T9)    \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL10(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10)                  \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL11(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11)             \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL12(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12)        \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL13(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13)   \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL14(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13,   \
                                                        T14)                  \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M(); C<T14>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL15(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13,   \
                                                        T14, T15)             \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M(); C<T14>::M(); C<T15>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL16(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13,   \
                                                        T14, T15, T16)        \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M(); C<T14>::M(); C<T15>::M();      \
        C<T16>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL17(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13,   \
                                                        T14, T15, T16, T17)   \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M(); C<T14>::M(); C<T15>::M();      \
        C<T16>::M(); C<T17>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL18(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13,   \
                                                        T14, T15, T16, T17,   \
                                                        T18)                  \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M(); C<T14>::M(); C<T15>::M();      \
        C<T16>::M(); C<T17>::M(); C<T18>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL19(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13,   \
                                                        T14, T15, T16, T17,   \
                                                        T18, T19)             \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M(); C<T14>::M(); C<T15>::M();      \
        C<T16>::M(); C<T17>::M(); C<T18>::M(); C<T19>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL20(C, M, T1, T2, T3, T4, \
                                                        T5, T6, T7, T8, T9,   \
                                                        T10, T11, T12, T13,   \
                                                        T14, T15, T16, T17,   \
                                                        T18, T19, T20)        \
        C<T1>::M(); C<T2>::M(); C<T3>::M(); C<T4>::M(); C<T5>::M();           \
        C<T6>::M(); C<T7>::M(); C<T8>::M(); C<T9>::M(); C<T10>::M();          \
        C<T11>::M(); C<T12>::M(); C<T13>::M(); C<T14>::M(); C<T15>::M();      \
        C<T16>::M(); C<T17>::M(); C<T18>::M(); C<T19>::M(); C<T20>::M();

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL(C, M, N, ...)           \
        BSLTF_TEMPLATETESTFACILITY_EXPAND(                                    \
         BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL ## N(C, M, __VA_ARGS__))

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_(C, M, N, ...)               \
        BSLTF_TEMPLATETESTFACILITY_EXPAND(                                    \
           BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_IMPL(C, M, N, __VA_ARGS__))

#define BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE(CLASS, METHOD, ...)          \
        BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE_(                            \
                            CLASS,                                            \
                            METHOD,                                           \
                            BSLTF_TEMPLATETESTFACILITY_NUM_ARGS(__VA_ARGS__), \
                            __VA_ARGS__)                                      \
        // Instantiates the specified 'CLASS' for each of the types specified
        // in the third to last arguments of this macro.  Call the specified
        // class 'METHOD' of each instantiation.  The compilation will fail if
        // the number of specified types is more than 20.

#define BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(TYPE)          \
        inline void dbg_print(const TYPE& val)                                \
       { printf("%d", bsltf::TemplateTestFacility::getIdentifier<TYPE>(val)); }

#define BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINTS()             \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                             bsltf::EnumeratedTestType::Enum) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                                        bsltf::UnionTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                                       bsltf::SimpleTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                                        bsltf::AllocTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                             bsltf::NonOptionalAllocTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                                 bsltf::MovableAllocTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                                      bsltf::MovableTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                                bsltf::MoveOnlyAllocTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                              bsltf::AllocEmplacableTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                                   bsltf::EmplacableTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                              bsltf::BitwiseCopyableTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                              bsltf::BitwiseMoveableTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                         bsltf::AllocBitwiseMoveableTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                          bsltf::NonTypicalOverloadsTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                         bsltf::NonCopyConstructibleTestType) \
                                                                              \
        BSLTF_TEMPLATETESTFACILITY_TEST_TYPES_DEFINE_DBG_PRINT(               \
                                      bsltf::NonDefaultConstructibleTestType)

    // Defines a list of 'dbg_print' overloads for use in the test driver.
    // FIXME: Change this to integrate with Alisdair's test driver print
    // facility once its ready.

#define BSLTF_TEMPLATETESTFACILITY_COMPARE_EQUAL(FIRST_ARGUMENT,              \
                                                 SECOND_ARGUMENT)             \
        ::BloombergLP::bsltf::TemplateTestFacility_CompareHelper::            \
                                    areEqual(FIRST_ARGUMENT, SECOND_ARGUMENT)

#define BSLTF_TEMPLATETESTFACILITY_COMPARE_NOT_EQUAL(FIRST_ARGUMENT,          \
                                                 SECOND_ARGUMENT)             \
        ::BloombergLP::bsltf::TemplateTestFacility_CompareHelper::            \
                                 areNotEqual(FIRST_ARGUMENT, SECOND_ARGUMENT)

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

                        // ------------------------------------
                        // class TemplateTestFacility_StubClass
                        // ------------------------------------

template <int IDENTIFIER>
int TemplateTestFacility_StubClass::method()
{
    return IDENTIFIER;
}

                        // ----------------------------------------
                        // class TemplateTestFacility_CompareHelper
                        // ----------------------------------------

template <class TYPE>
inline
bool TemplateTestFacility_CompareHelper::areEqual(const TYPE& lhs,
                                                  const TYPE& rhs)
{
    return lhs == rhs;
}

template <class TYPE>
inline
bool TemplateTestFacility_CompareHelper::areNotEqual(const TYPE& lhs,
                                                     const TYPE& rhs)
{
    return lhs != rhs;
}

inline
bool TemplateTestFacility_CompareHelper::areEqual(
                                         const NonEqualComparableTestType& lhs,
                                         const NonEqualComparableTestType& rhs)
{
    return lhs.data() == rhs.data();
}

inline
bool TemplateTestFacility_CompareHelper::areNotEqual(
                                         const NonEqualComparableTestType& lhs,
                                         const NonEqualComparableTestType& rhs)
{
    return lhs.data() != rhs.data();
}

                        // ---------------------------
                        // struct TemplateTestFacility
                        // ---------------------------

// CLASS METHODS
template <class TYPE>
inline
TYPE TemplateTestFacility::create(int identifier)
{
    bsls::ObjectBuffer<TYPE> obj;
    emplace(obj.address(),
            identifier,
            &bslma::MallocFreeAllocator::singleton());
    bslma::DestructorGuard<TYPE> destructor(obj.address());
    return TYPE(bslmf::MovableRefUtil::move(obj.object()));
}

template <class TYPE, class ALLOCATOR>
inline
void TemplateTestFacility::emplace(TYPE      *address,
                                   int        identifier,
                                   ALLOCATOR  allocator)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    bsl::allocator_traits<ALLOCATOR>::construct(
                                               allocator, address, identifier);
}

template <class TYPE, class ALLOCATOR>
inline
void TemplateTestFacility::emplace(TYPE      *address,
                                   int        identifier,
                                   ALLOCATOR *allocator)
{
    emplace(address, identifier, bsl::allocator<TYPE>(allocator));
}

template <class TYPE, class ALLOCATOR>
inline
void TemplateTestFacility::emplace(TYPE **address, int identifier, ALLOCATOR)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = reinterpret_cast<TYPE *>(bsls::Types::IntPtr(identifier));
}

template <class TYPE, class ALLOCATOR>
inline
void TemplateTestFacility::emplace(TYPE **address, int identifier, ALLOCATOR *)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = reinterpret_cast<TYPE *>(bsls::Types::IntPtr(identifier));
}

template <class ALLOCATOR>
void TemplateTestFacility::emplace(const char **address,
                                   int          identifier,
                                   ALLOCATOR    allocator)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    (void)allocator;

    *address = nullTerminatedStringForIdentifier(identifier);
}

template <class ALLOCATOR>
void TemplateTestFacility::emplace(const char **address,
                                   int          identifier,
                                   ALLOCATOR   *allocator)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    (void)allocator;

    *address = nullTerminatedStringForIdentifier(identifier);
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(char *address, int identifier, ALLOCATOR)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = static_cast<char>(identifier);
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(char *address,
                                   int   identifier,
                                   ALLOCATOR *)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = static_cast<char>(identifier);
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(signed char *address,
                                   int          identifier,
                                   ALLOCATOR)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = static_cast<signed char>(identifier);
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(signed char *address,
                                   int          identifier,
                                   ALLOCATOR *)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = static_cast<signed char>(identifier);
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(EnumeratedTestType::Enum *address,
                                   int                       identifier,
                                   ALLOCATOR)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = static_cast<EnumeratedTestType::Enum>(identifier);
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(EnumeratedTestType::Enum *address,
                                   int                       identifier,
                                   ALLOCATOR *)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    *address = static_cast<EnumeratedTestType::Enum>(identifier);
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(TemplateTestFacility::MethodPtr *address,
                                   int                              identifier,
                                   ALLOCATOR)
{
    BSLS_ASSERT_SAFE(address);
    BSLS_ASSERT_SAFE(0 <= identifier);  BSLS_ASSERT_SAFE(identifier < 128);

    switch (identifier) {
      case   0: *address =                                           0 ; break;
      case   1: *address = &TemplateTestFacility_StubClass::method<  1>; break;
      case   2: *address = &TemplateTestFacility_StubClass::method<  2>; break;
      case   3: *address = &TemplateTestFacility_StubClass::method<  3>; break;
      case   4: *address = &TemplateTestFacility_StubClass::method<  4>; break;
      case   5: *address = &TemplateTestFacility_StubClass::method<  5>; break;
      case   6: *address = &TemplateTestFacility_StubClass::method<  6>; break;
      case   7: *address = &TemplateTestFacility_StubClass::method<  7>; break;
      case   8: *address = &TemplateTestFacility_StubClass::method<  8>; break;
      case   9: *address = &TemplateTestFacility_StubClass::method<  9>; break;
      case  10: *address = &TemplateTestFacility_StubClass::method< 10>; break;
      case  11: *address = &TemplateTestFacility_StubClass::method< 11>; break;
      case  12: *address = &TemplateTestFacility_StubClass::method< 12>; break;
      case  13: *address = &TemplateTestFacility_StubClass::method< 13>; break;
      case  14: *address = &TemplateTestFacility_StubClass::method< 14>; break;
      case  15: *address = &TemplateTestFacility_StubClass::method< 15>; break;
      case  16: *address = &TemplateTestFacility_StubClass::method< 16>; break;
      case  17: *address = &TemplateTestFacility_StubClass::method< 17>; break;
      case  18: *address = &TemplateTestFacility_StubClass::method< 18>; break;
      case  19: *address = &TemplateTestFacility_StubClass::method< 19>; break;
      case  20: *address = &TemplateTestFacility_StubClass::method< 20>; break;
      case  21: *address = &TemplateTestFacility_StubClass::method< 21>; break;
      case  22: *address = &TemplateTestFacility_StubClass::method< 22>; break;
      case  23: *address = &TemplateTestFacility_StubClass::method< 23>; break;
      case  24: *address = &TemplateTestFacility_StubClass::method< 24>; break;
      case  25: *address = &TemplateTestFacility_StubClass::method< 25>; break;
      case  26: *address = &TemplateTestFacility_StubClass::method< 26>; break;
      case  27: *address = &TemplateTestFacility_StubClass::method< 27>; break;
      case  28: *address = &TemplateTestFacility_StubClass::method< 28>; break;
      case  29: *address = &TemplateTestFacility_StubClass::method< 29>; break;
      case  30: *address = &TemplateTestFacility_StubClass::method< 30>; break;
      case  31: *address = &TemplateTestFacility_StubClass::method< 31>; break;
      case  32: *address = &TemplateTestFacility_StubClass::method< 32>; break;
      case  33: *address = &TemplateTestFacility_StubClass::method< 33>; break;
      case  34: *address = &TemplateTestFacility_StubClass::method< 34>; break;
      case  35: *address = &TemplateTestFacility_StubClass::method< 35>; break;
      case  36: *address = &TemplateTestFacility_StubClass::method< 36>; break;
      case  37: *address = &TemplateTestFacility_StubClass::method< 37>; break;
      case  38: *address = &TemplateTestFacility_StubClass::method< 38>; break;
      case  39: *address = &TemplateTestFacility_StubClass::method< 39>; break;
      case  40: *address = &TemplateTestFacility_StubClass::method< 40>; break;
      case  41: *address = &TemplateTestFacility_StubClass::method< 41>; break;
      case  42: *address = &TemplateTestFacility_StubClass::method< 42>; break;
      case  43: *address = &TemplateTestFacility_StubClass::method< 43>; break;
      case  44: *address = &TemplateTestFacility_StubClass::method< 44>; break;
      case  45: *address = &TemplateTestFacility_StubClass::method< 45>; break;
      case  46: *address = &TemplateTestFacility_StubClass::method< 46>; break;
      case  47: *address = &TemplateTestFacility_StubClass::method< 47>; break;
      case  48: *address = &TemplateTestFacility_StubClass::method< 48>; break;
      case  49: *address = &TemplateTestFacility_StubClass::method< 49>; break;
      case  50: *address = &TemplateTestFacility_StubClass::method< 50>; break;
      case  51: *address = &TemplateTestFacility_StubClass::method< 51>; break;
      case  52: *address = &TemplateTestFacility_StubClass::method< 52>; break;
      case  53: *address = &TemplateTestFacility_StubClass::method< 53>; break;
      case  54: *address = &TemplateTestFacility_StubClass::method< 54>; break;
      case  55: *address = &TemplateTestFacility_StubClass::method< 55>; break;
      case  56: *address = &TemplateTestFacility_StubClass::method< 56>; break;
      case  57: *address = &TemplateTestFacility_StubClass::method< 57>; break;
      case  58: *address = &TemplateTestFacility_StubClass::method< 58>; break;
      case  59: *address = &TemplateTestFacility_StubClass::method< 59>; break;
      case  60: *address = &TemplateTestFacility_StubClass::method< 60>; break;
      case  61: *address = &TemplateTestFacility_StubClass::method< 61>; break;
      case  62: *address = &TemplateTestFacility_StubClass::method< 62>; break;
      case  63: *address = &TemplateTestFacility_StubClass::method< 63>; break;
      case  64: *address = &TemplateTestFacility_StubClass::method< 64>; break;
      case  65: *address = &TemplateTestFacility_StubClass::method< 65>; break;
      case  66: *address = &TemplateTestFacility_StubClass::method< 66>; break;
      case  67: *address = &TemplateTestFacility_StubClass::method< 67>; break;
      case  68: *address = &TemplateTestFacility_StubClass::method< 68>; break;
      case  69: *address = &TemplateTestFacility_StubClass::method< 69>; break;
      case  70: *address = &TemplateTestFacility_StubClass::method< 70>; break;
      case  71: *address = &TemplateTestFacility_StubClass::method< 71>; break;
      case  72: *address = &TemplateTestFacility_StubClass::method< 72>; break;
      case  73: *address = &TemplateTestFacility_StubClass::method< 73>; break;
      case  74: *address = &TemplateTestFacility_StubClass::method< 74>; break;
      case  75: *address = &TemplateTestFacility_StubClass::method< 75>; break;
      case  76: *address = &TemplateTestFacility_StubClass::method< 76>; break;
      case  77: *address = &TemplateTestFacility_StubClass::method< 77>; break;
      case  78: *address = &TemplateTestFacility_StubClass::method< 78>; break;
      case  79: *address = &TemplateTestFacility_StubClass::method< 79>; break;
      case  80: *address = &TemplateTestFacility_StubClass::method< 80>; break;
      case  81: *address = &TemplateTestFacility_StubClass::method< 81>; break;
      case  82: *address = &TemplateTestFacility_StubClass::method< 82>; break;
      case  83: *address = &TemplateTestFacility_StubClass::method< 83>; break;
      case  84: *address = &TemplateTestFacility_StubClass::method< 84>; break;
      case  85: *address = &TemplateTestFacility_StubClass::method< 85>; break;
      case  86: *address = &TemplateTestFacility_StubClass::method< 86>; break;
      case  87: *address = &TemplateTestFacility_StubClass::method< 87>; break;
      case  88: *address = &TemplateTestFacility_StubClass::method< 88>; break;
      case  89: *address = &TemplateTestFacility_StubClass::method< 89>; break;
      case  90: *address = &TemplateTestFacility_StubClass::method< 90>; break;
      case  91: *address = &TemplateTestFacility_StubClass::method< 91>; break;
      case  92: *address = &TemplateTestFacility_StubClass::method< 92>; break;
      case  93: *address = &TemplateTestFacility_StubClass::method< 93>; break;
      case  94: *address = &TemplateTestFacility_StubClass::method< 94>; break;
      case  95: *address = &TemplateTestFacility_StubClass::method< 95>; break;
      case  96: *address = &TemplateTestFacility_StubClass::method< 96>; break;
      case  97: *address = &TemplateTestFacility_StubClass::method< 97>; break;
      case  98: *address = &TemplateTestFacility_StubClass::method< 98>; break;
      case  99: *address = &TemplateTestFacility_StubClass::method< 99>; break;
      case 100: *address = &TemplateTestFacility_StubClass::method<100>; break;
      case 101: *address = &TemplateTestFacility_StubClass::method<101>; break;
      case 102: *address = &TemplateTestFacility_StubClass::method<102>; break;
      case 103: *address = &TemplateTestFacility_StubClass::method<103>; break;
      case 104: *address = &TemplateTestFacility_StubClass::method<104>; break;
      case 105: *address = &TemplateTestFacility_StubClass::method<105>; break;
      case 106: *address = &TemplateTestFacility_StubClass::method<106>; break;
      case 107: *address = &TemplateTestFacility_StubClass::method<107>; break;
      case 108: *address = &TemplateTestFacility_StubClass::method<108>; break;
      case 109: *address = &TemplateTestFacility_StubClass::method<109>; break;
      case 110: *address = &TemplateTestFacility_StubClass::method<110>; break;
      case 111: *address = &TemplateTestFacility_StubClass::method<111>; break;
      case 112: *address = &TemplateTestFacility_StubClass::method<112>; break;
      case 113: *address = &TemplateTestFacility_StubClass::method<113>; break;
      case 114: *address = &TemplateTestFacility_StubClass::method<114>; break;
      case 115: *address = &TemplateTestFacility_StubClass::method<115>; break;
      case 116: *address = &TemplateTestFacility_StubClass::method<116>; break;
      case 117: *address = &TemplateTestFacility_StubClass::method<117>; break;
      case 118: *address = &TemplateTestFacility_StubClass::method<118>; break;
      case 119: *address = &TemplateTestFacility_StubClass::method<119>; break;
      case 120: *address = &TemplateTestFacility_StubClass::method<120>; break;
      case 121: *address = &TemplateTestFacility_StubClass::method<121>; break;
      case 122: *address = &TemplateTestFacility_StubClass::method<122>; break;
      case 123: *address = &TemplateTestFacility_StubClass::method<123>; break;
      case 124: *address = &TemplateTestFacility_StubClass::method<124>; break;
      case 125: *address = &TemplateTestFacility_StubClass::method<125>; break;
      case 126: *address = &TemplateTestFacility_StubClass::method<126>; break;
      case 127: *address = &TemplateTestFacility_StubClass::method<127>; break;
      default : {
        BSLS_ASSERT_OPT_UNREACHABLE("`identifier` out of range [0..127]");
      }
    }
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(MethodPtr *address,
                                   int        identifier,
                                   ALLOCATOR *allocator)
{
    emplace(address, identifier, bsl::allocator<MethodPtr>(allocator));
}

// TBD: still working on this as part of C++11 project but should not affect
//      component test drivers
template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(EmplacableTestType *address,
                                   int                 identifier,
                                   ALLOCATOR           allocator)
{
    BSLS_ASSERT_SAFE(identifier >= 0);
    BSLS_ASSERT_SAFE(identifier < 128);

    EmplacableTestType::ArgType01 A01(identifier);
    EmplacableTestType::ArgType02 A02(  20);
    EmplacableTestType::ArgType03 A03(  23);
    EmplacableTestType::ArgType04 A04(  44);
    EmplacableTestType::ArgType05 A05(  66);
    EmplacableTestType::ArgType06 A06( 176);
    EmplacableTestType::ArgType07 A07( 878);
    EmplacableTestType::ArgType08 A08(   8);
    EmplacableTestType::ArgType09 A09( 912);
    EmplacableTestType::ArgType10 A10( 102);
    EmplacableTestType::ArgType11 A11( 111);
    EmplacableTestType::ArgType12 A12( 333);
    EmplacableTestType::ArgType13 A13( 712);
    EmplacableTestType::ArgType14 A14(1414);

    switch (identifier) {
      case 0: {
        bsl::allocator_traits<ALLOCATOR>::construct(allocator, address);
      } break;
      case 1: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01));
      } break;
      case 2: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02));
      } break;
      case 3: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03));
      } break;
      case 4: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04));
      } break;
      case 5: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05));
      } break;
      case 6: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06));
      } break;
      case 7: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07));
      } break;
      case 8: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08));
      } break;
      case 9: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09));
      } break;
      case 10: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10));
      } break;
      case 11: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11));
      } break;
      case 12: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11),
                                           bslmf::MovableRefUtil::move(A12));
      } break;
      case 13: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11),
                                           bslmf::MovableRefUtil::move(A12),
                                           bslmf::MovableRefUtil::move(A13));
      } break;
      case 14: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11),
                                           bslmf::MovableRefUtil::move(A12),
                                           bslmf::MovableRefUtil::move(A13),
                                           bslmf::MovableRefUtil::move(A14));
      } break;
      default: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01));
      }
    }
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(EmplacableTestType *address,
                                   int                 identifier,
                                   ALLOCATOR          *allocator)
{
    emplace(address,
            identifier,
            bsl::allocator<EmplacableTestType>(allocator));
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(AllocEmplacableTestType *address,
                                   int                      identifier,
                                   ALLOCATOR                allocator)
{
    BSLS_ASSERT_SAFE(identifier >= 0);
    BSLS_ASSERT_SAFE(identifier < 128);

    AllocEmplacableTestType::ArgType01 A01(identifier, allocator);
    AllocEmplacableTestType::ArgType02 A02(  20, allocator);
    AllocEmplacableTestType::ArgType03 A03(  23, allocator);
    AllocEmplacableTestType::ArgType04 A04(  44, allocator);
    AllocEmplacableTestType::ArgType05 A05(  66, allocator);
    AllocEmplacableTestType::ArgType06 A06( 176, allocator);
    AllocEmplacableTestType::ArgType07 A07( 878, allocator);
    AllocEmplacableTestType::ArgType08 A08(   8, allocator);
    AllocEmplacableTestType::ArgType09 A09( 912, allocator);
    AllocEmplacableTestType::ArgType10 A10( 102, allocator);
    AllocEmplacableTestType::ArgType11 A11( 111, allocator);
    AllocEmplacableTestType::ArgType12 A12( 333, allocator);
    AllocEmplacableTestType::ArgType13 A13( 712, allocator);
    AllocEmplacableTestType::ArgType14 A14(1414, allocator);

    switch (identifier) {
      case 0: {
        bsl::allocator_traits<ALLOCATOR>::construct(allocator, address);
      } break;
      case 1: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01));
      } break;
      case 2: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02));
      } break;
      case 3: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03));
      } break;
      case 4: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04));
      } break;
      case 5: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05));
      } break;
      case 6: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06));
      } break;
      case 7: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07));
      } break;
      case 8: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08));
      } break;
      case 9: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09));
      } break;
      case 10: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10));
      } break;
      case 11: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11));
      } break;
      case 12: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11),
                                           bslmf::MovableRefUtil::move(A12));
      } break;
      case 13: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11),
                                           bslmf::MovableRefUtil::move(A12),
                                           bslmf::MovableRefUtil::move(A13));
      } break;
      case 14: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01),
                                           bslmf::MovableRefUtil::move(A02),
                                           bslmf::MovableRefUtil::move(A03),
                                           bslmf::MovableRefUtil::move(A04),
                                           bslmf::MovableRefUtil::move(A05),
                                           bslmf::MovableRefUtil::move(A06),
                                           bslmf::MovableRefUtil::move(A07),
                                           bslmf::MovableRefUtil::move(A08),
                                           bslmf::MovableRefUtil::move(A09),
                                           bslmf::MovableRefUtil::move(A10),
                                           bslmf::MovableRefUtil::move(A11),
                                           bslmf::MovableRefUtil::move(A12),
                                           bslmf::MovableRefUtil::move(A13),
                                           bslmf::MovableRefUtil::move(A14));
      } break;
      default: {
        bsl::allocator_traits<ALLOCATOR>::construct(
                                           allocator,
                                           address,
                                           bslmf::MovableRefUtil::move(A01));
      }
    }
}

template <class ALLOCATOR>
inline
void TemplateTestFacility::emplace(AllocEmplacableTestType *address,
                                   int                      identifier,
                                   ALLOCATOR               *allocator)
{
    emplace(address,
            identifier,
            bsl::allocator<EmplacableTestType>(allocator));
}

template <class TYPE>
inline
int TemplateTestFacility::getIdentifier(TYPE*const& object)
{
    bsls::Types::IntPtr result = reinterpret_cast<bsls::Types::IntPtr>(object);
    return static_cast<int>(result);
}

template <class TYPE>
inline
int TemplateTestFacility::getIdentifier(const TYPE& object)
{
    BSLMF_ASSERT((!bsl::is_same<TYPE, const char *>::value));
    // The static assertion catches most improper use of calling this function
    // with an explicit instantiation: 'getIdentifier<TYPE>(obj)'.  Calls to
    // this function should always rely on type deduction to determine 'TYPE'
    // and pick the correct overload for this template.

    return static_cast<int>(object);
}

inline
int TemplateTestFacility::getIdentifier(const char*const& object)
{
    return object ? atoi(object) : 0;
}

template <class ALLOC>
inline
int TemplateTestFacility::getIdentifier(const StdAllocTestType<ALLOC>& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<
    bsltf::TemplateTestFacility::MethodPtr>(
                             const bsltf::TemplateTestFacility::MethodPtr& ptr)
{
    if (!ptr) {
        return 0;                                                     // RETURN
    }

    TemplateTestFacility_StubClass object = TemplateTestFacility_StubClass();
    return (object.*ptr)();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::UnionTestType>(
                                            const bsltf::UnionTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::SimpleTestType>(
                                           const bsltf::SimpleTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::AllocTestType>(
                                            const bsltf::AllocTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::NonOptionalAllocTestType>(
                                 const bsltf::NonOptionalAllocTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::MovableAllocTestType>(
                                     const bsltf::MovableAllocTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::MovableTestType>(
                                          const bsltf::MovableTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::MoveOnlyAllocTestType>(
                                    const bsltf::MoveOnlyAllocTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::BitwiseCopyableTestType>(
                                  const bsltf::BitwiseCopyableTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::BitwiseMoveableTestType>(
                                  const bsltf::BitwiseMoveableTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::AllocBitwiseMoveableTestType>(
                             const bsltf::AllocBitwiseMoveableTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::NonTypicalOverloadsTestType>(
                              const bsltf::NonTypicalOverloadsTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::NonAssignableTestType>(
                                    const bsltf::NonAssignableTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<
    bsltf::NonCopyConstructibleTestType>(
                             const bsltf::NonCopyConstructibleTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<
    bsltf::NonDefaultConstructibleTestType>(
                          const bsltf::NonDefaultConstructibleTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::NonEqualComparableTestType>(
                               const bsltf::NonEqualComparableTestType& object)
{
    return object.data();
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::EmplacableTestType>(
                               const bsltf::EmplacableTestType& object)
{
    BSLS_ASSERT_SAFE(   1 <= object.arg01() || 128 > object.arg01());
    BSLS_ASSERT_SAFE(  20 == object.arg02() || -1 == object.arg02());
    BSLS_ASSERT_SAFE(  23 == object.arg03() || -1 == object.arg03());
    BSLS_ASSERT_SAFE(  44 == object.arg04() || -1 == object.arg04());
    BSLS_ASSERT_SAFE(  66 == object.arg05() || -1 == object.arg05());
    BSLS_ASSERT_SAFE( 176 == object.arg06() || -1 == object.arg06());
    BSLS_ASSERT_SAFE( 878 == object.arg07() || -1 == object.arg07());
    BSLS_ASSERT_SAFE(   8 == object.arg08() || -1 == object.arg08());
    BSLS_ASSERT_SAFE( 912 == object.arg09() || -1 == object.arg09());
    BSLS_ASSERT_SAFE( 102 == object.arg10() || -1 == object.arg10());
    BSLS_ASSERT_SAFE( 111 == object.arg11() || -1 == object.arg11());
    BSLS_ASSERT_SAFE( 333 == object.arg12() || -1 == object.arg12());
    BSLS_ASSERT_SAFE( 712 == object.arg13() || -1 == object.arg13());
    BSLS_ASSERT_SAFE(1414 == object.arg14() || -1 == object.arg14());

    return -1 == object.arg01() ?  0
         : -1 == object.arg02() ?  object.arg01()
         : -1 == object.arg03() ?  2
         : -1 == object.arg04() ?  3
         : -1 == object.arg05() ?  4
         : -1 == object.arg06() ?  5
         : -1 == object.arg07() ?  6
         : -1 == object.arg08() ?  7
         : -1 == object.arg09() ?  8
         : -1 == object.arg10() ?  9
         : -1 == object.arg11() ? 10
         : -1 == object.arg12() ? 11
         : -1 == object.arg13() ? 12
         : -1 == object.arg14() ? 13
         :                        14;
}

template <>
inline
int TemplateTestFacility::getIdentifier<bsltf::AllocEmplacableTestType>(
                               const bsltf::AllocEmplacableTestType& object)
{
    BSLS_ASSERT_SAFE(   1 == object.arg01() || -1 == object.arg01());
    BSLS_ASSERT_SAFE(  20 == object.arg02() || -1 == object.arg02());
    BSLS_ASSERT_SAFE(  23 == object.arg03() || -1 == object.arg03());
    BSLS_ASSERT_SAFE(  44 == object.arg04() || -1 == object.arg04());
    BSLS_ASSERT_SAFE(  66 == object.arg05() || -1 == object.arg05());
    BSLS_ASSERT_SAFE( 176 == object.arg06() || -1 == object.arg06());
    BSLS_ASSERT_SAFE( 878 == object.arg07() || -1 == object.arg07());
    BSLS_ASSERT_SAFE(   8 == object.arg08() || -1 == object.arg08());
    BSLS_ASSERT_SAFE( 912 == object.arg09() || -1 == object.arg09());
    BSLS_ASSERT_SAFE( 102 == object.arg10() || -1 == object.arg10());
    BSLS_ASSERT_SAFE( 111 == object.arg11() || -1 == object.arg11());
    BSLS_ASSERT_SAFE( 333 == object.arg12() || -1 == object.arg12());
    BSLS_ASSERT_SAFE( 712 == object.arg13() || -1 == object.arg13());
    BSLS_ASSERT_SAFE(1414 == object.arg14() || -1 == object.arg14());

    return -1 == object.arg01() ?  0
         : -1 == object.arg02() ?  1
         : -1 == object.arg03() ?  2
         : -1 == object.arg04() ?  3
         : -1 == object.arg05() ?  4
         : -1 == object.arg06() ?  5
         : -1 == object.arg07() ?  6
         : -1 == object.arg08() ?  7
         : -1 == object.arg09() ?  8
         : -1 == object.arg10() ?  9
         : -1 == object.arg11() ? 10
         : -1 == object.arg12() ? 11
         : -1 == object.arg13() ? 12
         : -1 == object.arg14() ? 13
         :                        14;
}

template <>
inline
int TemplateTestFacility::getIdentifier<
                                      bsltf::WellBehavedMoveOnlyAllocTestType>(
                         const bsltf::WellBehavedMoveOnlyAllocTestType& object)
{
    return object.data();
}

template <class TYPE>
MoveState::Enum
TemplateTestFacility::getMovedFromState(const TYPE& object)
{
    return getMovedFrom(object);
}

template <class TYPE>
MoveState::Enum
TemplateTestFacility::getMovedIntoState(const TYPE& object)
{
    return getMovedInto(object);
}

template <class TYPE>
void TemplateTestFacility::setMovedIntoState(TYPE                   *object,
                                             bsltf::MoveState::Enum  value)
{
    setMovedInto(object, value);
}

// FREE FUNCTIONS
inline
void debugprint(const EnumeratedTestType::Enum& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const UnionTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const SimpleTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const AllocTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const NonOptionalAllocTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

template <class ALLOC>
inline
void debugprint(const StdAllocTestType<ALLOC>& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const MovableAllocTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const MovableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const MoveOnlyAllocTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const BitwiseCopyableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const BitwiseMoveableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const AllocBitwiseMoveableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const NonTypicalOverloadsTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const NonAssignableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const NonCopyConstructibleTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const NonDefaultConstructibleTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const NonEqualComparableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const AllocEmplacableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const EmplacableTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

inline
void debugprint(const WellBehavedMoveOnlyAllocTestType& obj)
{
    printf("%d", bsltf::TemplateTestFacility::getIdentifier(obj));
}

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

#endif

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