// bsls_alignmentimp.h                                                -*-C++-*-
#ifndef INCLUDED_BSLS_ALIGNMENTIMP
#define INCLUDED_BSLS_ALIGNMENTIMP

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

//@PURPOSE: Provide implementation meta-functions for alignment computation.
//
//@CLASSES:
//  bsls::AlignmentImpCalc: 'TYPE' parameter to alignment 'VALUE' map
//  bsls::AlignmentImpMatch: namespace for overloaded 'match' functions
//  bsls::AlignmentImpPriorityToType: 'PRIORITY' param to primitive type map
//  bsls::AlignmentImpTag: unique type of size 'SIZE' (parameter)
//
//@SEE_ALSO: bsls_alignmentfromtype, bsls_alignmenttotype, bsls_alignmentutil
//
//@DESCRIPTION: This component provides a suite of template meta-functions that
// can be used to compute (at compile-time) various platform-dependent
// alignment information.  The clients of this component are expected to be
// 'bsls' components such as 'bsls_alignmentfromtype', 'bsls_alignmenttotype',
// and 'bsls_alignmentutil'.  Other client code should use one of these 'bsls'
// components instead of using this component directly.
//
///Computing Alignment for a Type
///------------------------------
// The compiler alignment for a given type, 'T', can be computed by creating a
// structure containing a single 'char' member followed by a 'T' member:
//..
//  struct X {
//      char d_c;
//      T    d_t;
//  };
//..
// The compiler lays this structure out in memory as follows:
//..
//  +---+---+-------+
//  |d_c| P |  d_t  |
//  +---+---+-------+
//..
// where 'P' is padding added by the compiler to ensure that 'd_t' is properly
// aligned.  The alignment for 'T' is the number of bytes from the start of the
// structure to the beginning of 'd_t', which is also the total size of the
// structure minus the size of 'd_t':
//..
//  bsls::AlignmentImpCalc<T>::VALUE == sizeof(X) - sizeof(T);
//..
// Since 'sizeof' yields a compile-time constant, the alignment can be computed
// at compile time.
//
///Computing a Type Requiring an Alignment
///---------------------------------------
// A considerably more difficult compile-time computation supported by this
// component is that of determining a fundamental type with the same alignment
// requirements of a given type 'T'.  This involves computing the alignment for
// 'T', as above, and then performing an alignment-to-type lookup, all at
// compile time.  The general principles of this computation follow.
//
// We would like to create a template class that is specialized for each
// fundamental type's alignment.  Unfortunately, multiple types will have the
// same alignment and the compiler would issue a diagnostic if the same
// specialization was defined more than once.  To disambiguate, we create a
// "priority" class for each fundamental type that arbitrarily ranks that type
// relative to all of the other fundamental types.  Each priority class is
// derived from the next-lower priority class.  A set of overloaded functions
// are created such that, given two fundamental types with the same alignment,
// overload resolution will pick the one with the highest priority (i.e., the
// most-derived priority type).  The 'sizeof' operator and several template
// specializations are used to determine the compiler's choice of overloaded
// 'match' function.  The return value is mapped to a priority, which is, in
// turn, mapped to an appropriate primitive type.
//
///Usage
///-----
// This section illustrates the intended use of this component.
//
///Example 1: 'AlignmentImpCalc' Template
/// - - - - - - - - - - - - - - - - - - -
// Suppose that we want to write a program that needs to calculate the
// alignment requirements of both user-defined types and built-in types.
// Further suppose that the program will run on a platform where the alignment
// requirement of 'int' is 4 bytes.
//
// First, we define a 'struct', 'MyStruct', for which want to determine the
// alignment requirement:
//..
//  struct MyStruct {
//      char  d_c;
//      int   d_i;
//      short d_s;
//  };
//..
// Note that 'int' is the most alignment-demanding type within 'MyStruct'.
//
// Now, we use 'AlignmentImpCalc' to calculate the alignments of two
// types, 'short' and the 'MyStruct' we just defined:
//..
//  enum {
//      SHORT_ALIGNMENT     = bsls::AlignmentImpCalc<short   >::VALUE,
//      MY_STRUCT_ALIGNMENT = bsls::AlignmentImpCalc<MyStruct>::VALUE };
//..
// Finally, we observe the values of our alignments, we observe that
// the size of the 2 objects is a multiple of each object's alignment
// (which is true for all C++ types), and we observe that the size of
// 'MyStruct' is greater than its alignment.
//..
//  assert(2 == SHORT_ALIGNMENT);
//  assert(4 == MY_STRUCT_ALIGNMENT);
//
//  assert(0 == sizeof(short   ) % SHORT_ALIGNMENT);
//  assert(0 == sizeof(MyStruct) % MY_STRUCT_ALIGNMENT);
//
//  assert(sizeof(MyStruct) > MY_STRUCT_ALIGNMENT);
//..
//
///Example 2: Types Supporting 'AlignmentToType'
///- - - - - - - - - - - - - - - - - - - - - - -
// Suppose we to be able to determine a fundamental or pointer type that has
// both its size and alignment requirement equal to the alignment requirement
// of a specified template parameter type.  We can use the 'AlignmentImpTag'
// 'struct' template, the overloads of 'AlignmentImpMatch::match' class method,
// the 'AiignmentImp_Priority' template class, and the
// 'AlignmentImpPrioriityToType' template class to do this calculation.
//
// First, we define a class template, 'ConvertAlignmentToType', that provides a
// 'Type' alias to a fundamental or pointer type that has both its alignment
// requirement and size equal to the compile-time constant 'ALIGNMENT' 'int'
// parameter of the template.
//..
//  template <int ALIGNMENT>
//  struct ConvertAlignmentToType {
//      // This 'struct' provides a 'typedef', 'Type', that aliases a primitive
//      // type having the specified 'ALIGNMENT' requirement and size.
//
//    private:
//      // PRIVATE TYPES
//      typedef typename bsls::AlignmentImpMatch::MaxPriority MaxPriority;
//          // 'MaxPriority' is a typedef to the 'AlignmentImp_Priority'
//          // template class having the highest permissible priority value.
//
//      typedef          bsls::AlignmentImpTag<ALIGNMENT>     Tag;
//          // 'Tag' provides a typedef to the 'AlignmentImpTag' class
//          // configured with this 'struct's 'ALIGNMENT' parameter.
//
//      enum {
//          // Compute the priority of the primitive type corresponding to the
//          // specified 'ALIGNMENT'.  Many 'match' functions are declared, and
//          // at least one whose alignment and size fields are identical and
//          // equal to 'ALIGNMENT'.  Of those who match, the first match will
//          // be the one with the highest priority 'AlignmentImp_Priority'
//          // arg.
//
//          PRIORITY = sizeof(bsls::AlignmentImpMatch::match(Tag(),
//                                                           Tag(),
//                                                           MaxPriority()))
//      };
//
//    public:
//      // TYPES
//      typedef typename bsls::AlignmentImpPriorityToType<PRIORITY>::Type Type;
//          // Convert the 'PRIORITY' value we calculated back to a type that
//          // has the value 'ALIGNMENT' for both its alignment and it's size.
//  };
//..
// Then, we define two user defined types on which we will use
// 'ConvertAlignmentToType' on:
//..
//  struct MyStructA {
//      short  d_s;
//      double d_d;
//      int    d_i;
//  };
//
//  struct MyStructB {
//      double d_d[20];
//  };
//..
// Here, we calculate alignments for our 3 types with 'AlignmentImpCalc'.
//..
//  const int INT_ALIGNMENT = bsls::AlignmentImpCalc<int      >::VALUE;
//  const int A_ALIGNMENT   = bsls::AlignmentImpCalc<MyStructA>::VALUE;
//  const int B_ALIGNMENT   = bsls::AlignmentImpCalc<MyStructB>::VALUE;
//..
// Now, for each alignment requirement we just calculated, we utilize
// 'ConvertAlignmentToType' to determine the fundamental or pointer
// type having both size and alignment requirement equal to the
// calculated alignment requirement:
//..
//  typedef ConvertAlignmentToType<INT_ALIGNMENT>::Type IntAlignType;
//  typedef ConvertAlignmentToType<A_ALIGNMENT  >::Type ThisAlignType;
//  typedef ConvertAlignmentToType<B_ALIGNMENT  >::Type ThatAlignType;
//..
// Finally, we observe that the alignments of the '*AlignType's are the
// same as the alignments of the types from which they are derived, and that
// all the type determined by 'ConvertAlignmentToType' have sizes
// equal to their alignment requirements:
//..
//  assert(INT_ALIGNMENT == bsls::AlignmentImpCalc<IntAlignType >::VALUE);
//  assert(A_ALIGNMENT   == bsls::AlignmentImpCalc<ThisAlignType>::VALUE);
//  assert(B_ALIGNMENT   == bsls::AlignmentImpCalc<ThatAlignType>::VALUE);
//
//  assert(INT_ALIGNMENT == sizeof(IntAlignType));
//  assert(A_ALIGNMENT   == sizeof(ThisAlignType));
//  assert(B_ALIGNMENT   == sizeof(ThatAlignType));
//..

#include <bsls_platform.h>

namespace BloombergLP {

namespace bsls {

                // ======================
                // struct AlignmentImpTag
                // ======================

template <int SIZE>
struct AlignmentImpTag {
    // This 'struct' defines a unique type having the specified compile-time
    // 'SIZE'.

    // DATA
    char d_dummy[SIZE];
};

                // =======================
                // struct AlignmentImpCalc
                // =======================

template <class TYPE>
struct AlignmentImpCalc {
    // This 'struct' provides an enumerator 'VALUE' that is initialized to the
    // required alignment for the specified 'TYPE'.

  private:
    // PRIVATE TYPES
    struct AlignmentCalc {
        // This private 'struct' computes the required alignment for 'TYPE'.
        // The compiler inserts sufficient padding after the 'char' member so
        // that 'd_aligned' is correctly aligned for 'TYPE'.  The distance from
        // the start of the structure to 'd_aligned' is the alignment of
        // 'TYPE', and is computed as follows:
        //..
        //  sizeof(AlignmentImpCalc<TYPE>::AlignmentCalc) - sizeof(TYPE)
        //..

        // DATA
        char d_c;
        TYPE d_aligned;

      private:
        // NOT IMPLEMENTED
        AlignmentCalc();
        AlignmentCalc(const AlignmentCalc&);
        ~AlignmentCalc();
            // Prevent the compiler from automatically generating
            // default & copy constructors and destructor, as this could cause
            // problems if 'TYPE' has constructors / destructor that are
            // private or unimplemented.
    };

  public:
    // TYPES
    enum {
        // Define the compile-time computed alignment value for 'TYPE'.

        VALUE = sizeof(AlignmentCalc) - sizeof(TYPE)
    };

    typedef AlignmentImpTag<VALUE> Tag;
        // Alias for the unique type for each alignment value.
};

#if defined(BSLS_PLATFORM_CPU_POWERPC) && defined(BSLS_PLATFORM_OS_LINUX)
template <>
struct AlignmentImpCalc <long double> {
    // This 'struct' provides an enumerator 'VALUE' that is initialized to the
    // required alignment for long double on Linux on POWER.  This template
    // specialization is for long double on Linux on POWER where default malloc
    // in glibc returns memory aligned to 8-bytes, not 16-bytes.  8-byte
    // alignment is sufficient for proper long double operation on POWER even
    // though 16-byte alignment is more optimal (and is required for vector
    // instructions).
    //
    // Note: the optional tcmalloc library returns memory aligned to 16-bytes.

  public:
    // TYPES
    enum {
        // Define the alignment value for long double on Linux on POWER.

        VALUE = 8
    };

    typedef AlignmentImpTag<VALUE> Tag;
        // Alias for the unique type for each alignment value.
};
#endif

                // ===================================
                // struct AlignmentImp8ByteAlignedType
                // ===================================

#if defined(BSLS_PLATFORM_CPU_X86)                                            \
 && (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG))
struct AlignmentImp8ByteAlignedType {
    // On Linux or Solaris x86, no natural type is aligned on an 8-byte
    // boundary, but we need such a type to implement low-level constructs
    // (e.g., 64-bit atomic types).

    long long d_dummy __attribute__((__aligned__(8)));
};
#endif

                // =================================
                // struct AlignmentImpPriorityToType
                // =================================

template <int PRIORITY>
struct AlignmentImpPriorityToType {
    // Specializations of this 'struct' provide a primitive type (as a 'Type'
    // 'typedef') that corresponds to the specified 'PRIORITY' level.
};

template <>
struct AlignmentImpPriorityToType< 1> {
    typedef long double Type;
};

template <>
struct AlignmentImpPriorityToType< 2> {
    typedef double      Type;
};

template <>
struct AlignmentImpPriorityToType< 3> {
    typedef float       Type;
};

template <>
struct AlignmentImpPriorityToType< 4> {
    typedef void      (*Type)();
};

template <>
struct AlignmentImpPriorityToType< 5> {
    typedef void       *Type;
};

template <>
struct AlignmentImpPriorityToType< 6> {
    typedef wchar_t     Type;
};

template <>
struct AlignmentImpPriorityToType< 7> {
    typedef bool        Type;
};

template <>
struct AlignmentImpPriorityToType< 8> {
    typedef long long   Type;
};

template <>
struct AlignmentImpPriorityToType< 9> {
    typedef long        Type;
};

template <>
struct AlignmentImpPriorityToType<10> {
    typedef int         Type;
};

template <>
struct AlignmentImpPriorityToType<11> {
    typedef short       Type;
};

template <>
struct AlignmentImpPriorityToType<12> {
    typedef char        Type;
};

#if defined(BSLS_PLATFORM_CPU_X86)                                            \
 && (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG))
template <>
struct AlignmentImpPriorityToType<13> {
    typedef AlignmentImp8ByteAlignedType Type;
};
#endif

                // ============================
                // struct AlignmentImp_Priority
                // ============================

template <int VALUE>
struct AlignmentImp_Priority : AlignmentImp_Priority<VALUE - 1> {
    // This 'struct' provides a unique type that can be used as a trailing
    // function parameter for overloaded functions having otherwise identical
    // parameters.  The highest-priority overloaded function can be selected by
    // calling it with a high-priority argument.  Note that "highest priority"
    // means the largest 'VALUE' in this case.
};

template <>
struct AlignmentImp_Priority<1> {
    // Specialization of 'AlignmentImp_Priority' to terminate template
    // instantiation.
};

}  // close package namespace

namespace bsls {

    // Declare a 'match' function that is overloaded based on the alignment and
    // size of type 'T'.  The function has no implementation since it is used
    // only at compile-time to select the appropriate type for a given
    // alignment.  Return a tag that can used to look up a type using
    // 'AlignmentImpPriorityToType<P>::Type'.  Since multiple types can have
    // the same alignment and size, duplicate definitions are avoided by
    // overloading the function based on the priority 'P'.  When used, the
    // 'match' function with the highest priority is selected automatically.

                // ========================
                // struct AlignmentImpMatch
                // ========================

struct AlignmentImpMatch {
    // Namespace for a set of overloaded 'match' functions, as defined by the
    // macro 'BSLS_ALIGNMENTIMP_MATCH_FUNC'.

#   define BSLS_ALIGNMENTIMP_MATCH_FUNC(T, P)                                 \
           bsls::AlignmentImpTag<P> match(                                    \
                          bsls::AlignmentImpCalc<T>::Tag,                     \
                          bsls::AlignmentImpTag<static_cast<int>(sizeof(T))>, \
                          bsls::AlignmentImp_Priority<P>)

    // CLASS METHODS
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(long double,                        1);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(double,                             2);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(float,                              3);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(void (*)(),                         4);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(void *,                             5);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(wchar_t,                            6);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(bool,                               7);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(long long,                          8);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(long,                               9);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(int,                               10);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(short,                             11);
    static BSLS_ALIGNMENTIMP_MATCH_FUNC(char,                              12);
        // This function will match a type with the size and alignment the size
        // of the type of the first macro argument, and return an object whose
        // size is the 2nd argument of the macro.

#if defined(BSLS_PLATFORM_CPU_X86)                                            \
 && (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG))
        // This type exists, and is needed, only on Linux

    static BSLS_ALIGNMENTIMP_MATCH_FUNC(AlignmentImp8ByteAlignedType,      13);
#endif

    typedef AlignmentImp_Priority<13> MaxPriority;
};

}  // close package namespace

#undef BSLS_ALIGNMENTIMP_MATCH_FUNC

#ifndef BDE_OPENSOURCE_PUBLICATION  // BACKWARD_COMPATIBILITY
// ============================================================================
//                           BACKWARD COMPATIBILITY
// ============================================================================

#if defined(BSLS_PLATFORM_CPU_X86)                                            \
 && (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG))
typedef bsls::AlignmentImp8ByteAlignedType bsls_AlignmentImp8ByteAlignedType;
    // This alias is defined for backward compatibility.
#endif

#ifdef bsls_AlignmentImpTag
#undef bsls_AlignmentImpTag
#endif
#define bsls_AlignmentImpTag bsls::AlignmentImpTag
    // This alias is defined for backward compatibility.

#ifdef bsls_AlignmentImpPriorityToType
#undef bsls_AlignmentImpPriorityToType
#endif
#define bsls_AlignmentImpPriorityToType bsls::AlignmentImpPriorityToType
    // This alias is defined for backward compatibility.

typedef bsls::AlignmentImpMatch bsls_AlignmentImpMatch;
    // This alias is defined for backward compatibility.

#ifdef bsls_AlignmentImpCalc
#undef bsls_AlignmentImpCalc
#endif
#define bsls_AlignmentImpCalc bsls::AlignmentImpCalc
    // This alias is defined for backward compatibility.
#endif  // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY

}  // close enterprise namespace

#endif

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