// bdlma_alignedallocator.h                                           -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BDLMA_ALIGNEDALLOCATOR
#define INCLUDED_BDLMA_ALIGNEDALLOCATOR

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

//@PURPOSE: Provide a protocol for memory allocators that support alignment.
//
//@CLASSES:
//  bdlma::AlignedAllocator: protocol for aligned memory allocators
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component provides an implementation,
// 'bdlma::AlignedAllocator', of the base-level protocol (pure abstract
// interface) class, 'bslma::Allocator', providing the ability to allocate raw
// memory with a specified alignment.  The following inheritance diagram shows
// the classes involved and their methods:
//..
//   ,----------------------.
//  ( bdlma::AlignedAllocator )
//   `----------------------'
//               |       allocateAligned
//               V
//       ,----------------.
//      ( bslma::Allocator )
//       `----------------'
//                       allocate
//                       deallocate
//..
// The 'allocateAligned' method supplies the address of a contiguous block of
// allocated memory of at least the indicated size, that is aligned to a given
// boundary.  Note that this behavior is similar to the behavior of the POSIX
// function 'posix_memalign'.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Implementing 'bdlma::AlignedAllocator'
/// - - - - - - - - - - - - - - - - - - - - - - - -
// The 'bdlma::AlignedAllocator' protocol provided in this component defines a
// bilateral contract between suppliers and consumers of raw aligned memory.
// In order for the 'bdlma::AlignedAllocator' interface to be useful, we must
// supply a concrete allocator that implements it.
//
// In this example, we demonstrate how to adapt 'posix_memalign' on Linux and
// AIX, 'memalign' on SunOS and '_aligned_malloc' on Windows, to this protocol
// base class:
//
// First, we specify the interface of the concrete implementation of
// 'MyAlignedAllocator:
//..
//  // myposixmemalignallocator.h
//  // ...
//
//  class MyAlignedAllocator: public bdlma::AlignedAllocator {
//      // This class is a sample concrete implementation of the
//      // 'bdlma::AlignedAllocator' protocol that provides direct access to
//      // the system-supplied 'posix_memalign' and 'free' on Linux and AIX
//      // platforms, 'memalign' and 'free' on SunOS, or '_aligned_malloc' and
//      // '_aligned_free' on Windows.
//
//    private:
//      // NOT IMPLEMENTED
//      MyAlignedAllocator(const MyAlignedAllocator&);
//      MyAlignedAllocator& operator=(const MyAlignedAllocator&);
//
//    public:
//      // CREATORS
//      MyAlignedAllocator();
//          // Create a 'MyAlignedAllocator' object.  Note that all objects of
//          // this class share the same underlying resource.
//
//      virtual ~MyAlignedAllocator();
//          // Destroy this object.  Note that destroying this object has no
//          // effect on any outstanding allocated memory.
//
//      // MANIPULATORS
//      virtual void *allocate(bsls::Types::size_type size);
//          // Return a newly allocated block of memory of (at least) the
//          // specified positive 'size' (in bytes).  If 'size' is 0, a null
//          // pointer is returned with no other effect.  If this allocator
//          // cannot return the requested number of bytes, then it will throw
//          // an 'std::bad_alloc' exception in an exception-enabled build, or
//          // else it will abort the program in a non-exception build.  The
//          // behavior is undefined unless '0 <= size'.   Note that the
//          // alignment of the address returned conforms to the platform
//          // requirement for any object of the 'size'.  Also note that global
//          // 'operator new' is *not* called when 'size' is 0 (in order to
//          // avoid having to acquire a lock, and potential contention in
//          // multi-threaded programs).
//
//      virtual void *allocateAligned(bsls::Types::size_type size,
//                                    bsls::Types::size_type alignment);
//          // Return the address of a newly allocated block of memory of at
//          // least the specified positive 'size' (in bytes), sufficiently
//          // aligned such that the returned 'address' satisfies, for the
//          // specified 'alignment', '0 == (address & (alignment - 1))'.  If
//          // 'size' is 0, a null pointer is returned with no other effect.
//          // If the requested number of appropriately aligned bytes cannot be
//          // returned, then a 'bsl::bad_alloc' exception is thrown, or in a
//          // non-exception build the program is terminated.  The behavior is
//          // undefined unless 'alignment' is both a multiple of
//          // 'sizeof(void *)' and an integral non-negative power of two.
//
//      virtual void deallocate(void *address);
//          // Return the memory block at the specified 'address' back to this
//          // allocator.  If 'address' is 0, this function has no effect.  The
//          // behavior is undefined unless 'address' was allocated using this
//          // allocator object and has not already been deallocated.
//  };
//  // ...
//..
// Then, we implement the creators, trivially, as this class contains no
// instance data members.
//..
//  // CREATORS
//  MyAlignedAllocator::MyAlignedAllocator()
//  {
//  }
//
//  MyAlignedAllocator::~MyAlignedAllocator()
//  {
//  }
//..
// Now, we define the virtual methods of 'MyAlignedAllocator'.  Note that these
// definitions are not 'inline', as they would not be inlined when invoked from
// the base class (the typical usage in this case):
//..
//  // MANIPULATORS
//  void *MyAlignedAllocator::allocate(bsls::Types::size_type size)
//  {
//      if (0 == size) {
//          return 0;                                                 // RETURN
//      }
//
//      int alignment = bsls::AlignmentUtil::calculateAlignmentFromSize(size);
//      return allocateAligned(size, alignment);
//  }
//
//  void *MyAlignedAllocator::allocateAligned(bsls::Types::size_type size,
//                                            bsls::Types::size_type alignment)
//  {
//      BSLS_ASSERT_SAFE(0 == (alignment & (alignment - 1)));
//      BSLS_ASSERT_SAFE(0 == (alignment % sizeof(void *)));
//
//      if (0 == size) {
//          return 0;                                                 // RETURN
//      }
//
//      void *ret = 0;
//
//  #ifdef BSLS_PLATFORM_OS_WINDOWS
//      errno = 0;
//      ret = _aligned_malloc(size, alignment);
//      if (0 != errno) {
//          bsls::BslExceptionUtil::throwBadAlloc();
//      }
//  #elif defined(BSLS_PLATFORM_OS_SOLARIS)
//      ret = memalign(alignment, size);
//      if (0 == ret) {
//          bsls::BslExceptionUtil::throwBadAlloc();
//      }
//  #else
//      int rc = ::posix_memalign(&ret, alignment, size);
//      if (0 != rc) {
//          bsls::BslExceptionUtil::throwBadAlloc();
//      }
//  #endif
//
//      return ret;
//  }
//
//  void MyAlignedAllocator::deallocate(void *address)
//  {
//      if (0 == address) {
//          return;                                                   // RETURN
//      }
//  #ifdef BSLS_PLATFORM_WINDOWS
//      _aligned_free(address);
//  #else
//      ::free(address);
//  #endif
//  }
//..
// Finally, we define a function 'f' that instantiates an object of type
// 'MyAlignedAllocator':
//..
//  void f() {
//      MyAlignedAllocator a;
//  }
//..
// Note that the memory is not released when the allocator goes out of scope.
//
///Example 2: Using the 'bdlma::AlignedAllocator' Protocol
/// - - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example we illustrate how to use the 'bdlma::AlignedAllocator'
// protocol to allocate memory that is aligned to the beginning of a memory
// page.  Third party libraries, for example device drivers that perform DMA
// access of device drivers, or some extreme optimizations to reduce the number
// of page faults, might require page aligned allocations.
//
// First, we create an aligned allocator 'myAlignedAllocator' using the class
// 'MyAlignedAllocator' defined in the previous example, and obtain a
// 'bdlma::AlignedAllocator' pointer to it:
//..
//  MyAlignedAllocator myAlignedAllocator;
//  bdlma::AlignedAllocator *alignedAllocator = &myAlignedAllocator;
//..
// Now, assuming a page size of 4K, we allocate a buffer of 1024 bytes of
// memory and indicate that it should be aligned on a 4096 boundary:
//..
//  char *address = (char *) alignedAllocator->allocateAligned(1024, 4096);
//..
// Finally, we verify that the obtained address actually is aligned as
// expected:
//..
//  assert(0 == ((bsl::size_t)address & (4096 - 1)));
//..

#include <bslscm_version.h>

#include <bslma_allocator.h>

#include <bsls_annotation.h>
#include <bsls_platform.h>
#include <bsls_types.h>

#include <bsl_cstddef.h>

namespace BloombergLP {
namespace bdlma {

                          // ======================
                          // class AlignedAllocator
                          // ======================

class AlignedAllocator : public bslma::Allocator {
    // This protocol provides a pure abstract interface and contract for
    // clients and suppliers of raw aligned memory.  If the requested memory
    // cannot be returned, the contract requires that an 'std::bad_alloc'
    // exception be thrown.

  public:
    // MANIPULATORS
    virtual void *allocateAligned(bsls::Types::size_type size,
                                  bsls::Types::size_type alignment) = 0;
        // Return the address of a newly allocated block of memory of at least
        // the specified positive 'size' (in bytes), sufficiently aligned such
        // that the returned 'address' satisfies, for the specified
        // 'alignment', '0 == (address & (alignment - 1))'.  If 'size' is 0, a
        // null pointer is returned with no other effect.  If the requested
        // number of appropriately aligned bytes cannot be returned, then a
        // 'bsl::bad_alloc' exception is thrown, or in a non-exception build
        // the program is terminated.  The behavior is undefined unless
        // 'alignment' is both a multiple of 'sizeof(void *)' and an integral
        // non-negative power of two.
};

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

#endif

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