// bsls_alignmentutil.h                                               -*-C++-*-
#ifndef INCLUDED_BSLS_ALIGNMENTUTIL
#define INCLUDED_BSLS_ALIGNMENTUTIL

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

//@PURPOSE: Provide constants, types, and operations related to alignment.
//
//@CLASSES:
//  bsls::AlignmentUtil: namespace for alignment functions, types, and constants
//
//@SEE_ALSO: bslma_bufferimputil
//
//@DESCRIPTION: This component defines a 'struct', 'bsls::AlignmentUtil', which
// serves as a namespace for compile-time constants, types, and operations
// associated with alignment on the current platform.
//
// The 'BSLS_MAX_ALIGNMENT' enumerator provides the minimal value that
// satisfies the alignment requirements for all types on the current platform.
// Additionally, the 'MaxAlignedType' 'typedef' specifies a primitive type that
// requires an alignment of 'BSLS_MAX_ALIGNMENT'.
//
// The 'calculateAlignmentFromSize' function calculates a usable (but not
// necessarily minimal) alignment for any object with a memory footprint of the
// specified 'size' (in bytes).  The 'calculateAlignmentOffset' function
// calculates the offset from a specified 'address' where an object having a
// specified 'alignment' requirement can be constructed safely.  The
// 'is2ByteAligned', 'is4ByteAligned', and 'is8ByteAligned' functions each
// return 'true' if a specified 'address' is, respectively, 2-, 4-, or 8-byte
// aligned.  Finally, 'roundUpToMaximalAlignment' returns the smallest whole
// multiple of 'BSLS_MAX_ALIGNMENT' greater than or equal to its argument.
//
///Assumptions
///-----------
// The functionality in this component makes several assumptions:
//
//: o The alignment for any given type is an integral power of 2.
//:
//: o The required alignment for a type 'T' evenly divides 'sizeof(T)', which
//:   implies that the required alignment for 'T' is never larger than
//:   'sizeof(T)'.
//:
//: o The required alignment for a 'struct', 'class', or 'union' is the same as
//:   the required alignment of its most restrictive non-static data member
//:   (including the implicit virtual table pointer in polymorphic classes and
//:   internal pointers in virtually-derived classes).
//
///Usage
///-----
// A sequential memory allocator is used to return a sequence of memory blocks
// of varying requested sizes from a larger chunk of contiguous memory.  Each
// block returned must also have an alignment that is sufficient for any
// conceivable object of that size.  To achieve a fully factored
// implementation, we might choose to provide a low-level helper function
// 'naturallyAlign' that, given the 'address' of the next available byte in
// the larger chunk along with the requested block 'size' (in bytes), returns
// the first appropriately (or *naturally*) aligned address for the requested
// block at or after 'address':
//..
//  void *naturallyAlign(void **currentAddress, int size);
//      // Return the closest memory address at or after the specified
//      // '*currentAddress' that is sufficiently aligned to accommodate any
//      // object of the specified 'size', and update '*currentAddress' to
//      // refer to the first available byte after the allocated object.  The
//      // behavior is undefined unless '1 <= size'.
//..
// We can implement the 'naturallyAlign' helper function easily using the
// methods defined in this class:
//..
//  void *naturallyAlign(void **currentAddress, std::size_t size)
//  {
//      int   alignment = bsls::AlignmentUtil::calculateAlignmentFromSize(
//                                                              size);
//      int   offset    = bsls::AlignmentUtil::calculateAlignmentOffset(
//                                                             *currentAddress,
//                                                              alignment);
//      char *result    = static_cast<char *>(*currentAddress) + offset;
//      *currentAddress = result + size;
//      return result;
//  }
//..
// We will then be able to use this 'naturallyAlign' helper function to
// allocate, from a buffer of contiguous memory, efficiently (but not
// necessarily optimally) aligned memory for objects of varying sizes based
// solely on the size of each object (i.e., determined by its natural, not
// actual, alignment).
//
// To illustrate the functionality provided in this component, we begin by
// assuming that we have some user-defined type, 'MyType', comprising several
// data members:
//..
//  struct MyType {         // size 24; actual alignment 8; natural alignment 8
//      int     d_int;
//      double  d_double;   // Assume 8-byte alignment.
//      char   *d_charPtr;  // Assume size <= 8 bytes.
//  };
//..
// We then define a function, 'f', which starts off by creating a maximally
// aligned 'buffer' on the program stack:
//..
//  void f()
//  {
//      // The remainder of the usage example is in the USAGE test case.
//  }
//
//      union {
//          bsls::AlignmentUtil::MaxAlignedType d_dummy;  // force max. align.
//          char                                d_buffer[BUFFER_SIZE];
//      } buffer;
//..
// Next we use the 'bsls::AlignmentUtil' functions directly to confirm that
// 'buffer' is sufficiently aligned to accommodate a 'MaxAlignedType' object:
//..
//      int alignment = bsls::AlignmentFromType<
//                                 bsls::AlignmentUtil::MaxAlignedType>::VALUE;
//      int offset =
//                bsls::AlignmentUtil::calculateAlignmentOffset(
//                                                             buffer.d_buffer,
//                                                             alignment);
//      assert(0 == offset);  // sufficient alignment
//..
// Below we perform various memory allocations using our 'naturallyAlign'
// helper function:
//..
//      void *p         = static_cast<void *>(buffer.d_buffer);
//
//      (void)            naturallyAlign(&p, sizeof(char));
//
//      void *shortPtr5 = naturallyAlign(&p, 5 * sizeof(short));
//..
// Note that the address held in 'shortPtr' is numerically divisible by the
// alignment of a 'short' on the current platform:
//..
//      assert(0 == ((static_cast<char *>(shortPtr5) - buffer.d_buffer) %
//                                     bsls::AlignmentFromType<short>::VALUE));
//
//      assert(bsls::AlignmentUtil::is2ByteAligned(shortPtr5));
//..
// Next we use 'naturallyAlign' to allocate a block of appropriate size and
// sufficient alignment to store a 'MyType' object:
//..
//      void *objPtr = naturallyAlign(&p, sizeof(MyType));
//..
// Note that the alignment of the address held in 'objPtr' is numerically
// divisible by the actual alignment requirement:
//..
//      assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
//                                    objPtr,
//                                    bsls::AlignmentFromType<MyType>::VALUE));
//..
// Assuming 'buffer' has sufficient capacity, and the alignments for 'char',
// 'short', and 'MyType' are, respectively, 1, 2, and 8, we would expect this
// layout within 'buffer.d_buffer':
//..
//  charPtr shortPtr5                            objPtr
//  |       |                                                       |
//  V       V                                                       V
//  .---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.-
//  |ccc|   |sssssss:sssssss:sssssss:sssssss:sssssss|   :   :   :   |oooooo...
//  ^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^-
//  0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15  16  17  18
//..
// Note that on an atypical 32-bit platform where a 'double' is 4-byte
// aligned, the actual alignment of 'MyType' would be 4, but its natural
// alignment would still be 8 because its size would be 16; it is highly
// unlikely that 'MyType' would have an actual (and therefore natural)
// alignment of 4 on a 64-bit platform when using default compiler settings.

#include <bsls_alignmentfromtype.h>
#include <bsls_alignmentimp.h>
#include <bsls_alignmenttotype.h>
#include <bsls_assert.h>
#include <bsls_platform.h>
#include <bsls_types.h>

#include <limits>           // 'std::numeric_limits'

#include <cstddef>           // 'std::size_t'

namespace BloombergLP {

namespace bsls {

                            // ====================
                            // struct AlignmentUtil
                            // ====================

struct AlignmentUtil {
    // This 'struct' provides a namespace for a suite of compile-time
    // constants, types, and pure procedures that provide platform-dependent
    // alignment information.

  private:
    // PRIVATE TYPES
    typedef void (*FuncPtr)();
        // Typedef used as an alias for a function pointer.

    union MaxAlignedUnion;
    friend union MaxAlignedUnion;
        // Afford 'MaxAlignedUnion' access to the (private) 'FuncPtr' type.

    union MaxAlignedUnion {
        // This 'union' is guaranteed to be maximally aligned.  However, this
        // union is *not* a good candidate for 'MaxAlignedType' because it
        // might be larger than necessary.

        char         d_char;
        short        d_short;
        int          d_int;
        long         d_long;
        long long    d_longLong;
        bool         d_bool;
        wchar_t      d_wchar_t;
        void        *d_pointer;
        FuncPtr      d_funcPointer;
        float        d_float;
        double       d_double;
#if ! (defined(BSLS_PLATFORM_CPU_POWERPC) && defined(BSLS_PLATFORM_OS_LINUX))
        long double  d_longDouble;
#endif
#if defined(BSLS_PLATFORM_CPU_X86)                                            \
 && (defined(BSLS_PLATFORM_CMP_GNU) || defined(BSLS_PLATFORM_CMP_CLANG))      \
 && !defined(BSLS_PLATFORM_OS_SOLARIS)
        AlignmentImp8ByteAlignedType
                     d_8bytesAlignedType;
#endif
    };

  public:
    // CONSTANTS
    enum {
        // Define the minimal value that satisfies the alignment requirements
        // for all types.

        BSLS_MAX_ALIGNMENT = AlignmentFromType<MaxAlignedUnion>::VALUE
    };

    // TYPES
    typedef AlignmentToType<BSLS_MAX_ALIGNMENT>::Type MaxAlignedType;
        // Alias for a primitive type that has the most stringent alignment
        // requirement.

    // CLASS METHODS
    static int calculateAlignmentFromSize(std::size_t size);
        // Return the *natural* alignment for a memory block of the specified
        // size -- i.e., the largest power of 2 that evenly divides 'size', up
        // to a maximum of 'BSLS_MAX_ALIGNMENT'.  It is guaranteed that this
        // alignment will be sufficient for any object having a footprint of
        // 'size' bytes on the current platform.  The behavior is undefined
        // unless '1 <= size' and 'size <= INT_MAX'.  Note that, depending on
        // the machine architecture and compiler setting, the returned
        // alignment value may be more restrictive than required for a
        // particular object for two reasons:
        //: 1 The object may be composed entirely of elements, such as 'char',
        //:   that have minimal alignment restrictions, and
        //: 2 The architecture and our compiler settings may result in
        //:   unexpectedly lenient alignment requirements.
        // Also note that aligning on a more restrictive boundary may improve
        // performance.

    static int calculateAlignmentOffset(const void *address, int alignment);
        // Return the minimum non-negative integer that, when added to the
        // numerical value of the specified 'address', yields the specified
        // 'alignment'.  The behavior is undefined unless 'alignment' is a
        // positive, integral power of 2.

    static bool is2ByteAligned(const void *address);
        // Return 'true' if the specified 'address' is aligned on a 2-byte
        // boundary (i.e., the numerical value of 'address' is evenly divisible
        // by 2), and 'false' otherwise.

    static bool is4ByteAligned(const void *address);
        // Return 'true' if the specified 'address' is aligned on a 4-byte
        // boundary (i.e., the numerical value of 'address' is evenly divisible
        // by 4), and 'false' otherwise.

    static bool is8ByteAligned(const void *address);
        // Return 'true' if the specified 'address' is aligned on an 8-byte
        // boundary (i.e., the numerical value of 'address' is evenly divisible
        // by 8), and 'false' otherwise.

    static std::size_t roundUpToMaximalAlignment(std::size_t size);
        // Return the specified 'size' (in bytes) rounded up to the smallest
        // integral multiple of the maximum alignment.  The behavior is
        // undefined unless '0 <= size' and 'size' satisfies:
        //..
        //  size <= std::numeric_limits<std::size_t>::max()
        //          - BSLS_MAX_ALIGNMENT + 1
        //..
};

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

                            // ----------------
                            // struct Alignment
                            // ----------------

// CLASS METHODS
inline
int AlignmentUtil::calculateAlignmentFromSize(std::size_t size)
{
    ///IMPLEMENTATION NOTE
    ///-------------------
    // It is assumed that 'BSLS_MAX_ALIGNMENT' is a positive, integral power of
    // 2 (see the checks to that effect in the '.cpp' file).  For example,
    // suppose that 'BSLS_MAX_ALIGNMENT' is 16:
    //..
    //                                negated
    //                    modified    modified  intersect
    //  size     size       size       size       size     returned
    //  ----   --------   --------   --------   --------   --------
    //    0    00000000   00010000   11110000   00010000      16
    //    1    00000001   00010001   11101111   00000001       1
    //    2    00000010   00010010   11101110   00000010       2
    //    3    00000011   00010011   11101101   00000001       1
    //
    //    4    00000100   00010100   11101100   00000100       4
    //    5    00000101   00010101   11101011   00000001       1
    //    6    00000110   00010110   11101010   00000010       2
    //    7    00000110   00010111   11101001   00000001       1
    //
    //    8    00001000   00011000   11101000   00001000       8
    //    9    00001001   00011001   11100111   00000001       1
    //   10    00001010   00011010   11100110   00000010       2
    //   11    00001011   00011011   11100101   00000001       1
    //
    //   12    00001100   00011100   11100100   00000100       4
    //   13    00001101   00011101   11100011   00000001       1
    //   14    00001110   00011110   11100010   00000010       2
    //   15    00001110   00011111   11100001   00000001       1
    //
    //   16    00010000   00010000   11110000   00010000      16
    //   17    00010001   00010001   11101111   00000001       1
    //   18    00010010   00010010   11101110   00000010       2
    //   19    00010011   00010011   11101101   00000001       1
    //
    //   :         :          :          :         :           :
    //
    //   32    00100000   00110000   11010000   00010000      16
    //   33    00100001   00110001   11001111   00000001       1
    //   34    00100010   00110010   11001110   00000010       2
    //   35    00100011   00110011   11001101   00000001       1
    //
    //   :         :          :          :         :           :
    //..

    BSLS_ASSERT_SAFE(1 <= size);

    // It is safe to cast our value from a 'size_t' to an int, because all
    // bits that are higher order that 'BSLS_MAX_ALIGNMENT' are ignored by
    // the arithmetic that is done.

    int alignment = static_cast<int>(size | BSLS_MAX_ALIGNMENT);
    alignment &= -alignment;              // clear all but lowest order set bit

    // Verify at most one bit is set (should be impossible to fail)

    BSLS_ASSERT_SAFE(0 == (alignment & (alignment - 1)));

    return alignment;
}

inline
int AlignmentUtil::calculateAlignmentOffset(const void *address,
                                            int         alignment)
{
    BSLS_ASSERT_SAFE(1 <= alignment);
    BSLS_ASSERT_SAFE(0 == (alignment & (alignment - 1)));

    // Note that if 'address' is null, this function will correctly return zero
    // only if 'alignment' is a positive, integral power of 2.  Also note that
    // two other alternative implementations proved to be less efficient:
    //..
    //  return static_cast<int>(alignment - 1 -
    //               (reinterpret_cast<std::size_t>(address - 1)) % alignment);
    //..
    // and:
    //..
    //  const int mask = alignment - 1;
    //  return int(mask -
    //                  ((reinterpret_cast<std::size_t>(address - 1)) & mask));
    //..

    return static_cast<int>(
                           (alignment - reinterpret_cast<std::size_t>(address))
                         & (alignment - 1));
}

inline
bool AlignmentUtil::is2ByteAligned(const void *address)
{
    return 0 == (reinterpret_cast<std::size_t>(address) & 0x1);
}

inline
bool AlignmentUtil::is4ByteAligned(const void *address)
{
    return 0 == (reinterpret_cast<std::size_t>(address) & 0x3);
}

inline
bool AlignmentUtil::is8ByteAligned(const void *address)
{
    return 0 == (reinterpret_cast<std::size_t>(address) & 0x7);
}

inline
std::size_t AlignmentUtil::roundUpToMaximalAlignment(std::size_t size)
{
    BSLS_ASSERT_SAFE(size <= std::numeric_limits<std::size_t>::max()
                           - BSLS_MAX_ALIGNMENT + 1);

    return ((size + BSLS_MAX_ALIGNMENT - 1) / BSLS_MAX_ALIGNMENT)
                                                          * BSLS_MAX_ALIGNMENT;
}

}  // close package namespace

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

typedef bsls::AlignmentUtil bsls_AlignmentUtil;
    // 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 ----------------------------------