// bsls_alignment.h                                                   -*-C++-*-
#ifndef INCLUDED_BSLS_ALIGNMENT
#define INCLUDED_BSLS_ALIGNMENT

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

//@PURPOSE: Provide a namespace for enumerating memory alignment strategies.
//
//@CLASSES:
//  bsls::Alignment: namespace for enumerated alignment strategy values
//
//@SEE_ALSO: bsls_alignmentutil
//
//@DESCRIPTION: This component provides a namespace, 'bsls::Alignment', for
// enumerating alignment strategies, and provides a function, 'toAscii', that
// converts each of the enumerators to its corresponding string representation.
//
///Alignment Strategy
///------------------
// This component supports three alignment strategies: 1) MAXIMUM ALIGNMENT,
// 2) NATURAL ALIGNMENT, and 3) 1-BYTE ALIGNMENT.
//
//: 1 MAXIMUM ALIGNMENT: This strategy, as indicated by the enumerator
//:   'BSLS_MAXIMUM', specifies that a memory block be aligned as per the
//:   *most* restrictive alignment requirement on the host platform.
//:
//: 2 NATURAL ALIGNMENT: This strategy, as indicated by the enumerator
//:   'BSLS_NATURAL', specifies that a memory block be aligned based on the
//:   size (in bytes) of that block.  An object of a fundamental type ('int',
//:   etc.) is *naturally* *aligned* when its size evenly divides its address.
//:   An object of an aggregate type has natural alignment if the alignment of
//:   the most-restrictively aligned sub-object evenly divides the address of
//:   the aggregate.  Natural alignment is always at least as restrictive as
//:   the compiler's required alignment.
//:
//: 3 1-BYTE ALIGNMENT: This strategy, as indicated by the enumerator
//:   'BSLS_BYTEALIGNED', specifies that a memory block may be aligned
//:   arbitrarily on any 1-byte boundary.  This is the *least* restrictive
//:   alignment requirement.
//
///Usage
///-----
// Suppose that we want to create a static function, 'allocateFromBuffer', that
// takes a buffer, the size of the buffer, a cursor indicating a position
// within the buffer, an allocation request size, and a memory alignment
// strategy; 'allocateFromBuffer' returns a pointer to a block of memory,
// wholly contained within the buffer, having the specified size and alignment.
// As a side-effect, the cursor is updated to refer to the next available free
// byte in the buffer.  Such a function could be used by a memory manager to
// satisfy allocation requests from internally-managed buffers.  Clients of
// this function indicate which alignment strategy to use based on their
// specific requirements.
//
// Our 'allocateFromBuffer' function depends on an alignment utility,
// 'my_AlignmentUtil', whose minimal interface is limited to that required by
// this usage example.  (See the 'bsls_alignmentutil' component for a more
// realistic alignment utility.):
//..
//  struct my_AlignmentUtil {
//      // This 'struct' provides a namespace for basic types and utilities
//      // related to memory alignment.
//
//      // TYPES
//      enum {
//          MY_MAX_PLATFORM_ALIGNMENT = 8
//      };
//          // Provide the *minimal* value that satisfies the alignment
//          // requirements for *all* types on the host platform.  Note that 8
//          // is used for illustration purposes only; an actual implementation
//          // would employ template meta-programming to deduce the value at
//          // compile time.
//
//      // CLASS METHODS
//      static int calculateAlignmentFromSize(int size);
//          // Calculate a usable alignment for a memory block of the specified
//          // 'size' (in bytes) in the absence of compile-time knowledge of
//          // the block's alignment requirements.  Return the largest power of
//          // two that evenly divides 'size', up to a maximum of
//          // 'MY_MAX_PLATFORM_ALIGNMENT'.  It is guaranteed that a block of
//          // 'size' bytes can be safely aligned on the return value.   The
//          // behavior is undefined unless '0 < size'.
//
//      static int calculateAlignmentOffset(const void *address,
//                                          int         alignment);
//          // Return the smallest non-negative offset (in bytes) that, when
//          // added to the specified 'address', yields the specified
//          // 'alignment'.  The behavior is undefined unless '0 != alignment'
//          // and 'alignment' is a non-negative, integral power of 2.
//  };
//..
// The definition of our 'allocateFromBuffer' function is as follows:
//..
//  static void *allocateFromBuffer(int                       *cursor,
//                                  char                      *buffer,
//                                  int                        bufferSize,
//                                  int                        size,
//                                  bsls::Alignment::Strategy  strategy)
//      // Allocate a memory block of the specified 'size' (in bytes) from the
//      // specified 'buffer' having the specified 'bufferSize' at the
//      // specified 'cursor' position, using the specified alignment
//      // 'strategy'.  Return the address of the allocated memory block if
//      // 'buffer' contains sufficient available memory, and 0 otherwise.  The
//      // 'cursor' is set to the first byte position immediately after the
//      // allocated memory (which might be 1 byte past the end of 'buffer') if
//      // there is sufficient memory, and is not modified otherwise.  The
//      // behavior is undefined unless '0 <= bufferSize', '0 < size', and
//      // 'cursor' refers to a valid position in 'buffer'.
//  {
//..
// First we assert the function pre-conditions:
//..
//      assert(cursor);
//      assert(buffer);
//      assert(0 <= bufferSize);
//      assert(0 < size);
//..
// Then, based on the alignment 'strategy', we calculate the alignment value
// that can satisfy the allocation request.  In the case of
// 'bsls::Alignment::BSLS_NATURAL', we calculate the alignment from 'size'; for
// 'bsls::Alignment::BSLS_MAXIMUM', we use the platform-dependent
// 'my_AlignmentUtil::MY_MAX_PLATFORM_ALIGNMENT' value; and for
// 'bsls::Alignment::BSLS_BYTEALIGNED', we simply use 1:
//..
//      const int alignment =
//                         strategy == bsls::Alignment::BSLS_NATURAL
//                         ? my_AlignmentUtil::calculateAlignmentFromSize(size)
//                         : strategy == bsls::Alignment::BSLS_MAXIMUM
//                           ? my_AlignmentUtil::MY_MAX_PLATFORM_ALIGNMENT
//                           : 1;
//..
// Now we calculate the offset from the current 'cursor' value that can satisfy
// the 'alignment' requirements:
//..
//      const int offset = my_AlignmentUtil::calculateAlignmentOffset(
//                                                            buffer + *cursor,
//                                                            alignment);
//
//..
// Next we check if the available free memory in 'buffer' can satisfy the
// allocation request; 0 is returned if the request cannot be satisfied:
//..
//      if (*cursor + offset + size > bufferSize) {
//          return 0;                                                 // RETURN
//      }
//
//      void *result = &buffer[*cursor + offset];
//      *cursor += offset + size;
//
//..
// Finally, return the address of the correctly aligned memory block:
//..
//      return result;
//  }
//..
// The 'allocateFromBuffer' function may be used by a memory manager that needs
// to appropriately align memory blocks that are allocated from
// internally-managed buffers.  For an example, see the 'bslma_bufferimputil'
// component.

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsls_alignmentfromtype.h>
#include <bsls_alignmentimp.h>
#include <bsls_alignmenttotype.h>
#include <bsls_platform.h>

#include <cstddef>      // for std::size_t
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

// Temporarily define the legacy 'bsls_AlignmentOf' to refer to its
// replacement, 'bsls::AlignmentFromType'.

#ifndef bsls_AlignmentOf
#define bsls_AlignmentOf bsls::AlignmentFromType
#endif

// required for some code below wrapped in ifndef BDE_OMIT_INTERNAL_DEPRECATED

#include <bsls_alignmentutil.h>
#endif // BDE_OMIT_INTERNAL_DEPRECATED

namespace BloombergLP {

namespace bsls {

                        // ================
                        // struct Alignment
                        // ================

struct Alignment {
    // This 'struct' provides a namespace for enumerating the set of strategies
    // for aligning arbitrary blocks of memory.

    // TYPES
    enum Strategy {
        // Types of alignment strategy.

        BSLS_MAXIMUM = 0,
            // Align memory block based on the most restrictive alignment
            // requirements of the host platform.

        BSLS_NATURAL = 1,
            // Align memory block on an address that is the largest power of
            // two that evenly divides the size (in bytes) of the block.

        BSLS_BYTEALIGNED = 2
            // Align memory block based on the least restrictive alignment
            // requirements of the host platform (1-byte aligned).
    };

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    enum {
        // Define the minimum alignment that satisfies all types.
        //
        // DEPRECATED: This 'enum' is deprecated.  Use
        // 'AlignmentUtil::BSLS_MAX_ALIGNMENT instead.

        MAX_ALIGNMENT = AlignmentUtil::BSLS_MAX_ALIGNMENT
    };

    typedef AlignmentUtil::MaxAlignedType MaxAlignedType;
        // Primitive type with most stringent alignment requirement.
        //
        // DEPRECATED: Replaced by 'AlignmentUtil::MaxAlignedType'.

    struct Align {
        // 'struct' with most stringent alignment requirement.
        //
        // DEPRECATED: Replaced by 'Alignment::MaxAlignedType'.

        MaxAlignedType d_align;
    };
#endif // BDE_OMIT_INTERNAL_DEPRECATED

    // CLASS METHODS
    static const char *toAscii(Alignment::Strategy value);
        // Return the string representation of the specified enumerator
        // 'value'.  The string representation of 'value' matches its
        // corresponding enumerator name with the "BSLS_" prefix elided.  For
        // example:
        //..
        //  bsl::cout << Alignment::toAscii(Alignment::BSLS_NATURAL);
        //..
        // will print the following on standard output:
        //..
        //  NATURAL
        //..

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    static int calculateAlignmentFromSize(int size);
        // Calculate a usable alignment for an object of specified 'size' bytes
        // in the absence of compile-time knowledge of the object's alignment
        // requirements.  Return the largest power of two that evenly divides
        // size, up to a maximum of 'MAX_ALIGNMENT'.  It is guaranteed that an
        // object of 'size' bytes can be safely aligned on this return value.
        // Depending on the machine architecture and compiler options, the
        // returned alignment may be more than required for two reasons:
        //..
        //    1. The object may be composed entirely of elements, such as
        //       'char', which have minimal alignment restrictions.
        //
        //    2. The architecture may have lenient alignment requirements.
        //       Even if this is the case, aligning on a stricter boundary may
        //       improve performance.
        //..
        // The behavior is undefined unless '0 < size'.
        //
        // DEPRECATED: Replaced by 'AlignmentUtil::calculateAlignmentFromSize'.

    static int calculateAlignmentOffset(const void *address, int alignment);
        // Return the smallest non-negative offset in bytes that, when added to
        // the specified 'address', yields the specified 'alignment'.  The
        // behavior is undefined unless '0 < alignment' and 'alignment' is a
        // power of 2.
        //
        // DEPRECATED: Replaced by 'AlignmentUtil::calculateAlignmentOffset'.

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

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

    static bool is8ByteAligned(const void *address);
        // Return 'true' if the specified 'address' is aligned on an 8-byte
        // boundary (i.e., the integer value of 'address' is divisible by 8),
        // and 'false' otherwise.
        //
        // DEPRECATED: Replaced by 'AlignmentUtil::is8ByteAligned'.
#endif // BDE_OMIT_INTERNAL_DEPRECATED
};

}  // close package namespace

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

namespace bsls {

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

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

// CLASS METHODS
inline
int Alignment::calculateAlignmentFromSize(int size)
{
    return AlignmentUtil::calculateAlignmentFromSize(size);
}

inline
int Alignment::calculateAlignmentOffset(const void *address,
                                        int         alignment)
{
    return AlignmentUtil::calculateAlignmentOffset(address, alignment);
}

inline
bool Alignment::is2ByteAligned(const void *address)
{
    return AlignmentUtil::is2ByteAligned(address);
}

inline
bool Alignment::is4ByteAligned(const void *address)
{
    return AlignmentUtil::is4ByteAligned(address);
}

inline
bool Alignment::is8ByteAligned(const void *address)
{
    return AlignmentUtil::is8ByteAligned(address);
}

}  // close package namespace

#endif // BDE_OMIT_INTERNAL_DEPRECATED

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

typedef bsls::Alignment bsls_Alignment;
    // 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 ----------------------------------