// bslalg_typetraits.h                                                -*-C++-*-
#ifndef INCLUDED_BSLALG_TYPETRAITS
#define INCLUDED_BSLALG_TYPETRAITS

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

//@PURPOSE: Provide compile-time traits that can be associated with types.
//
//@DEPRECATED: Use 'bslmf_nestedtraitdeclaration' instead.
//
//@CLASSES:
//  bslalg::TypeTraitNil: nil type trait (no traits)
//  bslalg::TypeTraitBitwiseMoveable: bitwise-moveable trait
//  bslalg::TypeTraitBitwiseCopyable: bitwise-copyable trait
//  bslalg::TypeTraitBitwiseEqualityComparable: bitwise-eq.-comparable trait
//  bslalg::TypeTraitHasPointerSemantics: dereferences like a pointer
//  bslalg::TypeTraitHasStlIterators: has STL-like iterators
//  bslalg::TypeTraitHasTrivialDefaultConstructor: has trivial default ctor
//  bslalg::TypeTraitPair: for 'std::pair'-like classes
//  bslalg::TypeTraitUsesBslmaAllocator: uses 'bslma' allocators
//
//@MACROS:
//  BSLALG_DECLARE_NESTED_TRAITS: declares a trait in a nested fashion
//  BSLALG_DECLARE_NESTED_TRAITS2: declares two traits in a nested fashion
//  BSLALG_DECLARE_NESTED_TRAITS3: declares three traits in a nested fashion
//  BSLALG_DECLARE_NESTED_TRAITS4: declares four traits in a nested fashion
//  BSLALG_DECLARE_NESTED_TRAITS5: declares five traits in a nested fashion
//
//@SEE_ALSO: bslalg_constructorproxy, bslalg_scalarprimitives
//
//@DESCRIPTION: This component provides a set of type traits, and a set of
// macros used to assign traits to user-defined classes.  Traits are used to
// enable certain optimizations or discriminations at compile-time.  For
// instance, a class having the trait 'bslalg::TypeTraitBitwiseMoveable' may
// allow resizing an array of objects by simply calling 'std::memcpy' instead
// of invoking a copy-constructor on every object.  The usage example shows
// how to use the 'bslalg::TypeTraitUsesBslmaAllocator' to propagate allocators
// to nested objects that may require them.
//
// This component should be used in conjunction with other components from the
// package 'bslalg'.  See the package-level documentation for an overview.  The
// most useful classes and macros defined in this component are:
//..
//  Entity                                    Description
//  ------                                    -----------
//  bslalg::TypeTraitBitwiseMoveable         (See the corresponding class-level
//  bslalg::TypeTraitBitwiseCopyable                            documentation.)
//  bslalg::TypeTraitBitwiseEqualityComparable
//  bslalg::TypeTraitHasStlIterators
//  bslalg::TypeTraitHasTrivialDefaultConstructor
//  bslalg::TypeTraitPair
//  bslalg::TypeTraitUsesBslmaAllocator
//
//  BSLALG_DECLARE_NESTED_TRAITS(TYPE, TRAIT) A macro to attach a given 'TRAIT'
//                                            to a given type 'T' in a nested
//                                            fashion.  This macro must be used
//                                            within the 'public' section of a
//                                            class body.
//
//  bslalg::HasTrait<TYPE, TRAIT>             This meta-function computes
//                                            whether the parameterized 'TYPE'
//                                            possesses the parameterized
//                                            'TRAIT'.
//
//  bslalg::SelectTrait<T, TRAIT1, ...>       This meta-function selects the
//                                            first trait possessed by the
//                                            parameterized 'TYPE' from the
//                                            ordered list 'TRAIT1', ....
//..
//
///Usage
///-----
// In this usage example, we show how to enable the 'bslma' allocator model for
// generic containers, by implementing simplified versions of the
// 'bslalg_constructorproxy' and 'bslalg_scalarprimitives' components.  The
// interested reader should refer to the documentation of those components.
//
///A Generic Container
///- - - - - - - - - -
// Suppose we want to implement a generic container of a parameterized 'TYPE',
// which may or may not follow the 'bslma' allocator model.  If it does, our
// container should pass an extra 'bslma::Allocator*' argument to copy
// construct a value; but if it does not, then passing this extra argument is
// going to generate a compile-time error.  It thus appears we need two
// implementations of our container.  This can be done more succinctly by
// encapsulating into the constructor some utilities that will, through a
// single interface, determine whether 'TYPE' has the trait
// 'bslalg::TypeTraitUsesBslmaAllocator' and copy-construct it accordingly.
//
// The container contains a single data member of the parameterized 'TYPE'.
// Since we are going to initialize this data member manually, we do not want
// it to be automatically constructed by the compiler.  For this reason, we
// encapsulate it in a 'bsls::ObjectBuffer'.
//..
//  // my_genericcontainer.hpp                                        -*-C++-*-
//
//  template <class TYPE>
//  class MyGenericContainer {
//      // This generic container type contains a single object, always
//      // initialized, which can be replaced and accessed.  This container
//      // always takes an allocator argument and thus follows the
//      // 'bslalg::TypeTraitUsesBslmaAllocator' protocol.
//
//      // PRIVATE DATA MEMBERS
//      bsls::ObjectBuffer<TYPE> d_object;
//..
// Since the container offers a uniform interface that always takes an extra
// allocator argument, regardless of whether 'TYPE' does or not, we can declare
// it to have the 'bslalg::TypeTraitUsesBslmaAllocator' trait:
//..
//  public:
//    // TRAITS
//    BSLALG_DECLARE_NESTED_TRAITS(MyGenericContainer,
//                                 bslalg::TypeTraitUsesBslmaAllocator);
//..
// For simplicity, we let the container contain only a single element, and
// require that an element always be initialized.
//..
//  // CREATORS
//  explicit MyGenericContainer(const TYPE& object,
//                              bslma::Allocator *allocator = 0);
//      // Create a container containing the specified 'object', using the
//      // optionally specified 'allocator' to supply memory.  If 'allocator'
//      // is 0, the currently installed allocator is used.
//
//  MyGenericContainer(const MyGenericContainer&  container,
//                     bslma::Allocator          *allocator = 0);
//      // Create a container containing the same object as the specified
//      // 'container', using the optionally specified 'allocator' to supply
//      // memory.  If 'allocator' is 0, the currently installed allocator is
//      // used.
//
//  ~MyGenericContainer();
//      // Destroy this container.
//..
// We can also allow the container to change the object it contains, by
// granting modifiable as well as non-modifiable access to this object:
//..
//      // MANIPULATORS
//      TYPE& object();
//
//      // ACCESSORS
//      const TYPE& object() const;
//  };
//..
//
///Using the Type Traits
///- - - - - - - - - - -
// The challenge in the implementation lies in using the traits of the
// contained 'TYPE' to determine whether to pass the allocator argument to its
// copy constructor.  We rely here on a property of templates that templates
// are not compiled (and thus will not generate compilation errors) until they
// are instantiated.  Hence, we can use two function templates, and let the
// overloading resolution (based on the nested traits) decide which to
// instantiate.  The generic way to create an object, passing through all
// arguments (value and allocator) is as follows.  For brevity and to avoid
// breaking the flow of this example, we have embedded the function definition
// into the class.
//..
//  // my_genericcontainer.cpp  i                                     -*-C++-*-
//
//  struct my_GenericContainerUtil {
//      // This 'struct' provides a namespace for utilities implementing the
//      // allocator pass-through mechanism in a generic container.
//
//      template <class TYPE>
//      static void copyConstruct(TYPE             *location,
//                                const TYPE&       value,
//                                bslma::Allocator *allocator,
//                                bslalg::TypeTraitUsesBslmaAllocator)
//          // Create a copy of the specified 'value' at the specified
//          // 'location', using the specified 'allocator' to supply memory.
//      {
//          new (location) TYPE(value, allocator);
//      }
//..
// For types that don't use an allocator, we offer the following overload that
// will be selected if the type trait of 'TYPE' cannot be converted to
// 'bslalg::TypeTraitUsesBslmaAllocator'.  In that case, note that the type
// traits always inherit from 'bslalg::TypeTraitNil'.
//..
//  template <class TYPE>
//  static void copyConstruct(TYPE             *location,
//                            const TYPE&       value,
//                            bslma::Allocator *allocator,
//                            bslalg::TypeTraitNil)
//      // Create a copy of the specified 'value' at the specified
//      // 'location'.  Note that the specified 'allocator' is ignored.
//  {
//      new (location) TYPE(value);
//  }
//..
// And finally, this function will instantiate the type trait and pass it to
// the appropriately (compiler-)chosen overload:
//..
//      template <class TYPE>
//      static void copyConstruct(TYPE             *location,
//                                const TYPE&       value,
//                                bslma::Allocator *allocator)
//          // Create a copy of the specified 'value' at the specified
//          // 'location', optionally using the specified 'allocator' to supply
//          // memory if the parameterized 'TYPE' possesses the
//          // 'bslalg::TypeTraitUsesBslmaAllocator'.
//      {
//          copyConstruct(
//                 location, value, allocator,
//                 typename bsl::conditional<
//                        HasTrait<TYPE,
//                                 bslalg::TypeTraitUsesBslmaAllocator>::VALUE,
//                        bslalg::TypeTraitUsesBslmaAllocator,
//                        bslalg::TypeTraitNil>::type());
//      }
//  };
//..
//
///Generic Container Implementation
/// - - - - - - - - - - - - - - - -
// With these utilities, we can now implement 'MyGenericContainer'.
//..
//  // CREATORS
//  template <typename TYPE>
//  MyGenericContainer<TYPE>::MyGenericContainer(const TYPE&       object,
//                                               bslma::Allocator *allocator)
//  {
//      my_GenericContainerUtil::copyConstruct(&d_object.object(),
//                                             object,
//                                             allocator);
//  }
//
//  template <typename TYPE>
//  MyGenericContainer<TYPE>::MyGenericContainer(
//                                        const MyGenericContainer&  container,
//                                        bslma::Allocator          *allocator)
//  {
//      my_GenericContainerUtil::copyConstruct(&d_object.object(),
//                                             container.object(),
//                                             allocator);
//  }
//..
// Note that all this machinery only affects the constructors, and not the
// destructor which only invokes the destructor of 'd_object'.
//..
//  template <typename TYPE>
//  MyGenericContainer<TYPE>::~MyGenericContainer()
//  {
//      (&d_object.object())->~TYPE();
//  }
//..
// To finish, the accessors and manipulators are trivially implemented.
//..
//  // MANIPULATORS
//  template <typename TYPE>
//  TYPE& MyGenericContainer<TYPE>::object()
//  {
//      return d_object.object();
//  }
//
//  // ACCESSORS
//  template <typename TYPE>
//  const TYPE& MyGenericContainer<TYPE>::object() const
//  {
//      return d_object.object();
//  }
//..
//
///Usage Verification
/// - - - - - - - - -
// We can check that our container actually forwards the correct allocator to
// its contained objects with a very simple test apparatus, consisting of two
// classes that have exactly the same signature and implementation except that
// one has the 'bslalg::TypeTraitUsesBslmaAllocator' trait and the other does
// not:
//..
//  bslma::Allocator *allocSlot;
//
//  struct MyTestTypeWithBslmaAllocatorTraits {
//      // Class with declared traits.  Calling copy constructor without an
//      // allocator will compile, but will not set 'allocSlot'.
//
//      // TRAITS
//      BSLALG_DECLARE_NESTED_TRAITS(MyTestTypeWithBslmaAllocatorTraits,
//                           BloombergLP::bslalg::TypeTraitUsesBslmaAllocator);
//
//      // CREATORS
//      MyTestTypeWithBslmaAllocatorTraits() {}
//
//      MyTestTypeWithBslmaAllocatorTraits(
//                       const MyTestTypeWithBslmaAllocatorTraits&,
//                       bslma::Allocator                           *allocator)
//      {
//          allocSlot = allocator;
//      }
//  };
//
//  struct MyTestTypeWithNoBslmaAllocatorTraits {
//      // Class with no declared traits.  Calling copy constructor without
//      // an allocator will not set the 'allocSlot', but passing it by mistake
//      // will set it.
//
//      // CREATORS
//      MyTestTypeWithNoBslmaAllocatorTraits() {}
//
//      MyTestTypeWithNoBslmaAllocatorTraits(
//                    const MyTestTypeWithNoBslmaAllocatorTraits &,
//                    bslma::Allocator                              *allocator)
//      {
//          allocSlot = allocator;
//      }
//  };
//..
// Our verification program simply instantiates several 'MyGenericContainer'
// templates with the two test types above, and checks that the allocator slot
// is as expected:
//..
//  int main()
//  {
//      bslma::TestAllocator ta0;
//      bslma::TestAllocator ta1;
//..
// With 'MyTestTypeWithNoBslmaAllocatorTraits', the slot should never be set.
//..
//  MyTestTypeWithNoBslmaAllocatorTraits x;
//
//  allocSlot = &ta0;
//  MyGenericContainer<MyTestTypeWithNoBslmaAllocatorTraits> x0(x);
//  assert(&ta0 == allocSlot);
//
//  allocSlot = &ta0;
//  MyGenericContainer<MyTestTypeWithNoBslmaAllocatorTraits> x1(x, &ta1);
//  assert(&ta0 == allocSlot);
//..
// With 'MyTestTypeWithBslmaAllocatorTraits', the slot should be set to the
// allocator argument, or to 0 if not specified:
//..
//      MyTestTypeWithBslmaAllocatorTraits y;
//
//      allocSlot = &ta0;
//      MyGenericContainer<MyTestTypeWithBslmaAllocatorTraits> y0(y);
//      assert(0 == allocSlot);
//
//      allocSlot = &ta0;
//      MyGenericContainer<MyTestTypeWithBslmaAllocatorTraits> y1(y, &ta1);
//      assert(&ta1 == allocSlot);
//
//      return 0;
//  }
//..

#include <bslscm_version.h>

#include <bslalg_hastrait.h>
#include <bslalg_typetraitbitwisecopyable.h>
#include <bslalg_typetraitbitwiseequalitycomparable.h>
#include <bslalg_typetraitbitwisemoveable.h>
#include <bslalg_typetraithaspointersemantics.h>
#include <bslalg_typetraithasstliterators.h>
#include <bslalg_typetraithastrivialdefaultconstructor.h>
#include <bslalg_typetraitnil.h>
#include <bslalg_typetraitpair.h>
#include <bslalg_typetraitusesbslmaallocator.h>

namespace BloombergLP {

                    // ========================================
                    // macros BSLALG_DECLARE_NESTED_TRAITS[1-5]
                    // ========================================

#define BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT)            \
    operator TRAIT::NestedTraitDeclaration<T>() const {   \
        return TRAIT::NestedTraitDeclaration<T>();        \
    }
    // Associate the specified 'TRAIT' tag with the specified 'T' class.  This
    // macro must be invoked only within the public part of the definition of
    // class 'T'.  'TRAIT' must name a class such that
    // 'TRAIT::NestedTraitDeclaration<T>' designates a class derived from
    // 'bslmf::DetectNestedTrait'.

#define BSLALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2)                      \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2)
    // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for two traits.

#define BSLALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3)              \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3)
    // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for three traits.

#define BSLALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4)      \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT4)
    // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for four traits.

#define BSLALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5)  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT1);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT2);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT3);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT4);                                  \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAIT5)
    // Like 'BSLALG_DECLARE_NESTED_TRAITS', but for five traits.

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY

// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

#define BDEALG_DECLARE_NESTED_TRAITS(T, TRAITS)                               \
    BSLALG_DECLARE_NESTED_TRAITS(T, TRAITS)
    // This alias is defined for backward compatibility.

#define BDEALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2)                      \
    BSLALG_DECLARE_NESTED_TRAITS2(T, TRAIT1, TRAIT2)
    // This alias is defined for backward compatibility.

#define BDEALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3)              \
    BSLALG_DECLARE_NESTED_TRAITS3(T, TRAIT1, TRAIT2, TRAIT3)
    // This alias is defined for backward compatibility.

#define BDEALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4)      \
    BSLALG_DECLARE_NESTED_TRAITS4(T, TRAIT1, TRAIT2, TRAIT3, TRAIT4)
    // This alias is defined for backward compatibility.

#define BDEALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5)  \
    BSLALG_DECLARE_NESTED_TRAITS5(T, TRAIT1,TRAIT2,TRAIT3,TRAIT4,TRAIT5)
    // This alias is defined for backward compatibility.

#ifdef bdealg_HasTrait
#undef bdealg_HasTrait
#endif
#define bdealg_HasTrait bslalg::HasTrait
    // This alias is defined for backward compatibility.

#ifdef bdealg_SelectTrait
#undef bdealg_SelectTrait
#endif
#define bdealg_SelectTrait bslalg::SelectTrait
    // This alias is defined for backward compatibility.

#endif // BDE_OMIT_INTERNAL_DEPRECATED

#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // close enterprise namespace

#endif // INCLUDED_BSLALG_TYPETRAITS

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------