// bdlma_aligningallocator.h                                          -*-C++-*-
#ifndef INCLUDED_BDLMA_ALIGNINGALLOCATOR
#define INCLUDED_BDLMA_ALIGNINGALLOCATOR

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

//@PURPOSE: Provide an allocator-wrapper to allocate with a minimum alignment.
//
//@CLASSES:
//  bdlma::AligningAllocator: wrapper to align memory allocation
//
//@SEE_ALSO:
//
//@DESCRIPTION: This component defines a concrete allocator implementation,
// 'bdlma::AligningAllocator', providing the ability to allocate memory with a
// minimum alignment specified at the construction of the allocator.  The
// following inheritance diagram shows the classes involved and their methods:
//..
//   ,------------------------.
//  ( bdlma::AligningAllocator )
//   `------------------------'
//               |       ctor/dtor
//               |
//               V
//       ,----------------.
//      ( bslma::Allocator )
//       `----------------'
//                       allocate
//                       deallocate
//..
// The 'AligningAllocator' is supplied an allocator at construction, and
// ensures that memory returned by 'allocate' meets a minimum alignment
// requirement.  This may be useful in situations where a user needs to adapt
// an allocator supplying only natural alignment to software expecting an
// allocator with a higher alignment guarantee.  The allocator supplied to an
// 'AligningAllocator' at construction is held, not owned.
//
// The allocator supplied to the aligning allocator must employ at least the
// natural alignment strategy (see {'bsls_alignment'}).  Specifically, the
// aligning allocator will fail to properly align memory if the allocator
// passed to it employs the 1-byte alignment strategy.
//
// Note that in order to provide the requested alignment an 'AligningAllocator'
// will need to always overallocate memory from the underlying allocator.  This
// can "waste" space equal to the alignment plus some extra bytes for
// bookkeeping information.  For small allocations with large alignment values
// this waste can be very impactful.  In general, this means this component
// should be used with small alignments or with larger allocations.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Using 'bdlma::AligningAllocator'
///- - - - - - - - - - - - - - - - - - - - - -
// Suppose we are dealing with an externally supplied library function that
// creates a linked list of null-terminated strings, and we want to use a
// default-constructed buffered sequential allocator for memory allocation.
//
// First, the externally supplied library defines the 'struct' describing a
// node in the linked list:
//..
//  struct Node {
//      // This 'struct' describes one node in a linked list containing
//      // strings.
//
//      Node *d_next;
//      char  d_string[1];
//
//      // CLASS METHODS
//      static
//      bsl::size_t sizeNeededForString(const char *string)
//          // Return the size in bytes needed to store a 'Node' containing a
//          // copy of the specified 'string'.
//      {
//          Node node;
//
//          return sizeof(node.d_next) + bsl::strlen(string) + 1;
//      }
//  };
//..
// Then, the externally-supplied library defines the function that will create
// the linked list of nodes from a null-terminated array of pointers to
// C-strings:
//..
//  void externalPopulateStringList(Node             **head,
//                                  const char       **stringArray,
//                                  bslma::Allocator  *allocator)
//      // Create a linked list of strings beginning with the specified '*head'
//      // containing the null-terminated strings from the null-terminated
//      // 'stringArray'.  Use the specified 'allocator' to supply memory.
//  {
//      *head = 0;
//      const char *string;
//      for (int ii = 0; 0 != (string = stringArray[ii]); ++ii) {
//          Node *newNode = static_cast<Node *>(allocator->allocate(
//                                     Node::sizeNeededForString(string)));
//          assert(newNode != 0);
//
//          bsl::strcpy(newNode->d_string, string);
//
//          newNode->d_next = *head;
//          *head = newNode;
//      }
//  }
//..
// Next, our example function will begin with the externally-supplied buffered
// sequential allocator that we are to use:
//..
//  void printFromNodes(bsl::ostream *out) {
//      enum { k_BUFFER_SIZE = 4 * 1024 };
//      char                               buffer4k[k_BUFFER_SIZE];
//      bdlma::BufferedSequentialAllocator bsAlloc(buffer4k, k_BUFFER_SIZE);
//..
// There is a problem here, in that the nodes must be aligned by
// 'sizeof(Node *)', but our buffered sequential allocator, like most BDE
// allocators, has a "natural alignment" strategy (see {'bsls_alignment'}),
// meaning that it infers the required alignment from the size of the
// allocation requested.  This would normally give us properly aligned memory
// if we were allocating by 'sizeof(Node)', but our 'Node' objects are variable
// length, which will mislead the allocator to sometimes align the new segments
// by less than 'sizeof(Node *)'.
//
// Then, we solve this problem by using an aligning allocator to wrap the
// buffered sequential allocator, ensuring that the memory will still come from
// the buffered sequential allocator, but nonetheless be aligned to the
// alignment requirement of 'Node'.
//..
//      enum { k_ALIGNMENT = bsls::AlignmentFromType<Node>::VALUE };
//      bdlma::AligningAllocator aligningAllocator(k_ALIGNMENT, &bsAlloc);
//..
// Next, we define a null-terminated array of strings we would like to store in
// the list:
//..
//      const char *strings[] = {
//          "A zinger is not a rebuttal.\n",
//          "Humor is mankind's greatest blessing.\n",
//          "As usual, the facts don't care about our feelings.\n",
//          "Criticism is the only antidote to error.\n",
//          "If you can't annoy somebody, there is little point in writing.\n",
//          "Maybe all one can do is hope to end up with the right regrets.\n",
//          "People may hear your words, but they feel your attitude.\n",
//          "Imagination is a poor substitute for experience.\n",
//          "We wanted a labor force, but human beings came.\n",
//          "The reward of a thing well done is to have done it.\n",
//          "Chance fights ever on the side of the prudent.\n",
//          "The best time to make friends is before you need them.\n",
//          0  };
//..
// Now, we call the function to put the strings into a linked list, passing it
// the aligning allocator:
//..
//      Node *head = 0;
//      externalPopulateStringList(&head, strings, &aligningAllocator);
//..
// Finally, we traverse the list and print out the strings, verifying that the
// nodes are properly aligned:
//..
//      for (const Node *node = head; node; node = node->d_next) {
//          assert(0 == (reinterpret_cast<bsl::size_t>(node) &
//                       (k_ALIGNMENT - 1)));
//          if (out) {
//              *out << node->d_string;
//          }
//      }
//  }
//..

#include <bdlscm_version.h>

#include <bslma_allocator.h>

#include <bsls_keyword.h>
#include <bsls_types.h>

#include <bsl_cstddef.h>

namespace BloombergLP {
namespace bdlma {

                          // =======================
                          // class AligningAllocator
                          // =======================

class AligningAllocator : public bslma::Allocator {
    // This 'class' provides a mechanism that serves as a wrapper around
    // another allocator, passed at construction.  The mechanism guarantees
    // that all allocations passed to the underlying allocator will be aligned
    // by the alignment specified at construction.

    // DATA
    bsls::Types::size_type  d_mask;             // alignment - 1

    bslma::Allocator       *d_allocator_p;      // allocator indicated at
                                                // construction

  private:
    // NOT IMPLEMENTED
    AligningAllocator(const AligningAllocator&) BSLS_KEYWORD_DELETED;
    AligningAllocator& operator=(
                                const AligningAllocator&) BSLS_KEYWORD_DELETED;

  public:
    // CREATORS
    explicit AligningAllocator(bsls::Types::size_type  alignment,
                               bslma::Allocator       *basicAllocator = 0);
        // Create an 'AligningAllocator' object that guarantees alignment by
        // the specified 'alignment' (in bytes) of memory allocated.
        // Optionally specify a 'basicAllocator' used to supply memory.  If
        // 'basicAllocator' is 0 or not supplied, the currently installed
        // default allocator is used.  The behavior is undefined unless
        // 'alignment' is a power of 2, and the alignment strategy of the
        // alocator used to supply memory is 'BSLS_MAXIMUM' or 'BSLS_NATURAL'.

    // MANIPULATORS
    void *allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE;
        // 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 a 'std::bad_alloc'
        // exception in an exception-enabled build, or else will abort the
        // program in a non-exception build.  Note that the alignment of the
        // address returned conforms to the platform requirement for any object
        // of size 'size' and is also guaranteed to be at least the alignment
        // passed to the constructor.

    void deallocate(void *address) BSLS_KEYWORD_OVERRIDE;
        // 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.
};

}  // 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 ----------------------------------