// 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:
// ```
// /// This `struct` describes one node in a linked list containing strings.
// struct Node {
//
//     Node *d_next;
//     char  d_string[1];
//
//     // CLASS METHODS
//
//     /// Return the size in bytes needed to store a `Node` containing a
//     /// copy of the specified `string`.
//     static
//     bsl::size_t sizeNeededForString(const char *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:
// ```
// /// 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.
// void externalPopulateStringList(Node             **head,
//                                 const char       **stringArray,
//                                 bslma::Allocator  *allocator)
// {
//     *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
                          // =======================

/// 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.
class AligningAllocator : public bslma::Allocator {

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

    /// 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`.
    explicit AligningAllocator(bsls::Types::size_type  alignment,
                               bslma::Allocator       *basicAllocator = 0);

    // MANIPULATORS

    /// 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 *allocate(bsls::Types::size_type size) 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.
    void deallocate(void *address) BSLS_KEYWORD_OVERRIDE;
};

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