// bslma_bufferallocator.h                                            -*-C++-*-
#ifndef INCLUDED_BSLMA_BUFFERALLOCATOR
#define INCLUDED_BSLMA_BUFFERALLOCATOR

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

//@PURPOSE: Support efficient memory allocations from a user-supplied buffer.
//
//@INTERNAL_DEPRECATED: Use 'bdlma_bufferedsequentialallocator' instead.
//
//@CLASSES:
//  bslma::BufferAllocator: memory allocator from user-supplied buffer
//
//@SEE_ALSO: bdlma_bufferedsequentialallocator
//
//@DESCRIPTION: This component provides an allocator, 'bslma::BufferAllocator',
// that implements the 'bslma::Allocator' protocol and sequentially allocates
// memory blocks from a fixed-size buffer that is supplied by the user at
// construction.  If an allocation request exceeds the remaining space in the
// buffer, the return value is the result of invoking an optional callback
// function that was supplied at construction, or zero if no callback was
// specified.  This component also provides static utility functions for
// allocating memory directly from a user-specified buffer:
//..
//   ,----------------------.
//  ( bslma::BufferAllocator )
//   `----------------------'
//              |         ctor
//              V
//      ,----------------.
//     ( bslma::Allocator )
//      `----------------'
//                      allocate
//                      deallocate
//                      dtor
//..
//
///Alignment Strategy
///------------------
// The 'bslma::BufferAllocator' allocates memory using one of the two alignment
// strategies: 1) MAXIMUM ALIGNMENT or 2) NATURAL ALIGNMENT.
//
//: 1 MAXIMUM ALIGNMENT: This strategy always allocates memory aligned with the
//:   most restrictive alignment on the host platform.  The value is defined in
//:   'bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT'.
//:
//: 2 NATURAL ALIGNMENT: This strategy allocates memory whose alignment depends
//:   on the requested number of bytes.  An object of a fundamental type
//:   ('int', etc.) is *naturally* *aligned* when it's 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.  When only the size of
//:   an aggregate is known, and not its composition, we compute the alignment
//:   by finding the largest integral power of 2 (up to and including
//:   'bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT') that divides the requested
//:   (non-zero) number of bytes.  This computed alignment is guaranteed to be
//:   at least as restrictive as any sub-object within the aggregate.
//
///Usage
///-----
// The 'bslma::BufferAllocator' class defined in this component is commonly
// used to allocate memory from a static buffer that does not require
// "deletion".  The following snippet of code creates an array that obtains its
// memory from a fixed-sized buffer, but through the 'bslma::Allocator'
// protocol:
//..
//  // my_shortarray.h
//
//  // ...
//
//  namespace bslma { class Allocator; }
//
//  class my_ShortArray {
//      short            *d_array_p;      // dynamically-allocated array of
//                                        // 'short' integers
//
//      int               d_size;         // physical size of 'd_array_p'
//
//      int               d_length;       // logical length of 'd_array_p'
//
//      bslma::Allocator *d_allocator_p;  // memory allocator (held, not owned)
//
//    private:
//      // PRIVATE MANIPULATORS
//      void increaseSize();  // Increase the capacity by at least one element.
//
//    public:
//      // CREATORS
//      my_ShortArray(bslma::Allocator *basicAllocator);
//          // Create an empty array using the specified 'basicAllocator' to
//          // supply memory.
//      // ...
//
//      ~my_ShortArray();
//      void append(short value);
//      const short& operator[](int index) const { return d_array_p[index]; }
//      int length() const { return d_length; }
//  };
//..
// The implementation of 'my_ShortArray' is as follows:
//..
//  // my_shortarray.cpp
//  #include <my_shortarray.h>
//
//  enum { INITIAL_SIZE = 1, GROW_FACTOR = 2 };
//  // ...
//
//  my_ShortArray::my_ShortArray(bslma::Allocator *basicAllocator)
//  : d_size(INITIAL_SIZE)
//  , d_length(0)
//  , d_allocator_p(basicAllocator)
//  {
//      assert(d_allocator_p);
//      d_array_p =
//          (short *) d_allocator_p->allocate(d_size * sizeof *d_array_p);
//  }
//
//  my_ShortArray::~my_ShortArray()
//  {
//      // CLASS INVARIANTS
//      assert(d_array_p);
//      assert(0 <= d_size);
//      assert(0 <= d_length); assert(d_length <= d_size);
//      assert(d_allocator_p);
//
//      d_allocator_p->deallocate(d_array_p);
//  }
//
//  inline
//  void my_ShortArray::append(short value)
//  {
//      if (d_length >= d_size) {
//          increaseSize();
//      }
//      d_array_p[d_length++] = value;
//  }
//
//  static
//  void reallocate(short **array, int newSize, int length,
//                  bslma::Allocator *basicAllocator)
//      // Reallocate memory in the specified 'array' to the specified
//      // 'newSize' using the specified 'basicAllocator' or global new
//      // operator.  The specified 'length' number of leading elements are
//      // preserved.  Since the class invariant requires that the physical
//      // capacity of the container may grow but never shrink, the behavior
//      // is undefined unless length <= newSize.
//  {
//      assert(array);
//      assert(1 <= newSize);
//      assert(0 <= length);
//      assert(length <= newSize);        // enforce class invariant
//      assert(basicAllocator);
//
//      short *tmp = *array;              // support exception neutrality
//      *array = (short *) basicAllocator->allocate(newSize * sizeof **array);
//
//      // COMMIT POINT
//
//      memcpy(*array, tmp, length * sizeof **array);
//      basicAllocator->deallocate(tmp);
//  }
//
//  void my_ShortArray::increaseSize()
//  {
//       int proposedNewSize = d_size * GROW_FACTOR;    // reallocate can throw
//       assert(proposedNewSize > d_length);
//       reallocate(&d_array_p, proposedNewSize, d_length, d_allocator_p);
//       d_size = proposedNewSize;                      // we're committed
//  }
//  // ...
//..
// Use buffer allocator to allocate memory for 'my_ShortArray' as follows:
//..
//  void *callbackFunc(int /* size */)
//  {
//      std::cerr << "Buffer allocator out of memory." << std::endl;
//      exit(-1);
//      return (void *) 0;
//  }
//  // ...
//
//  int main(int argc, char *argv[])
//  {
//  // ...
//      static char memory[1024];  // No alignment issue; see below.
//      bslma::BufferAllocator allocator(memory, sizeof memory, callbackFunc);
//
//      my_ShortArray mA(allocator);
//      const my_ShortArray& A = mA;
//      mA.append(123);
//      mA.append(456);
//  // ...
//  }
//..
// Note that in the 'main' function above, 'memory' does not need to be aligned
// because 'bslma::BufferAllocator::allocate' internally performs alignment for
// each requested memory block based on the allocator's alignment strategy.

#ifdef BDE_OPENSOURCE_PUBLICATION // DEPRECATED
#error "bslma_bufferallocator is deprecated"
#endif
#include <bslscm_version.h>

#include <bslma_allocator.h>

namespace BloombergLP {

namespace bslma {

                        // =====================
                        // class BufferAllocator
                        // =====================

class BufferAllocator : public Allocator {
    // This 'class' provides a concrete buffer allocator that implements the
    // 'Allocator' interface, and allocates memory blocks from a fixed-size
    // buffer that is supplied by the user at construction.  The allocator can
    // supply memory that can be maximally (default) or naturally aligned.

  public:
    // TYPES
    typedef void *(*AllocCallback)(int);
        // 'AllocCallback' is an alias for (the address of) a function that
        // takes an integer argument and returns 'void *'.

    enum AlignmentStrategy {
        // Types of alignment strategy to allocate memory.

        MAXIMUM_ALIGNMENT,  // Default.  Return memory on maximally-aligned
                            // boundary
                            // 'bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT' (as
                            // required for ANSI standard allocators).

        NATURAL_ALIGNMENT   // Return memory aligned on a boundary that is the
                            // largest power of two dividing the requested size
                            // (up to
                            // 'bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT').
    };

  private:
    // DATA
    AlignmentStrategy  d_strategy;      // strategy to use for alignment
    int                d_cursor;        // position of the remaining free space
    char              *d_buffer_p;      // buffer for allocating memory
    int                d_bufferSize;    // size of the buffer
    AllocCallback      d_allocCallback; // function handling buffer overflow

    // NOT IMPLEMENTED
    BufferAllocator(const BufferAllocator&);
    BufferAllocator& operator=(const BufferAllocator&);

  public:
    // CLASS METHODS
    static void *allocateFromBuffer(int               *cursor,
                                    char              *buffer,
                                    size_type          bufSize,
                                    size_type          size,
                                    AlignmentStrategy  strategy);
    static void *allocateFromBuffer(int       *cursor,
                                    char      *buffer,
                                    size_type  bufSize,
                                    size_type  size,
                                    int        alignment);
        // Allocate a memory block of the specified 'size' from the specified
        // 'buffer' at the specified 'cursor' position.  Return the address of
        // the allocated memory block if 'buffer' contains enough available
        // memory, and 'null' otherwise.  The 'cursor' is set to the index of
        // the next available byte in 'buffer' after the allocation.  Use the
        // specified alignment 'strategy' (or 'alignment' value) to allocate
        // memory.  If 'size' is 0, do not allocate memory and return zero.
        // The behavior is undefined unless '0 < = bufSize', '0 <= size',
        // '0 < alignment <= bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT', and
        // alignment is an integral power of 2.

    // CREATORS
    BufferAllocator(char          *buffer,
                    size_type      bufSize,
                    AllocCallback  allocCallback = 0);
        // Create a buffer allocator for allocating memory blocks from the
        // specified 'buffer' of the specified 'bufSize'.  Optionally specify a
        // callback function 'allocCallback' that is invoked when a call to
        // 'allocate' cannot be fulfilled from 'buffer'.  Note that maximum
        // alignment is used when allocating memory.

    BufferAllocator(char              *buffer,
                    size_type          bufSize,
                    AlignmentStrategy  strategy,
                    AllocCallback      allocCallback = 0);
        // Create a buffer allocator for allocating memory blocks from the
        // specified 'buffer' of the specified 'bufSize'.  Use the specified
        // alignment 'strategy' to allocate memory.  Optionally specify a
        // callback function 'allocCallback' that is invoked when a call to
        // 'allocate' cannot be fulfilled from 'buffer'.

    ~BufferAllocator();
        // Destroy this buffer allocator.

    // MANIPULATORS
    void *allocate(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 return the result of
        // invoking an optional callback function (supplied at construction);
        // if no callback function was specified, throw a 'std::bad_alloc'
        // exception in an exception-enabled build, or else abort the program
        // in a non-exception build.  The behavior is undefined unless
        // '0 <= size'.  Note that the alignment of the address returned
        // depends on the alignment strategy ('MAXIMUM_ALIGNMENT' or
        // 'NATURAL_ALIGNMENT') specified at construction of this buffer
        // allocator.  Also note that it is up to the callback function whether
        // to return zero or throw an exception if this buffer allocator is
        // unable to satisfy the request.

    void deallocate(void *address);
        // This function has no effect for this buffer allocator.

    // ACCESSORS
    void print() const;
        // Write formatted debugging information to 'stdout' describing the
        // internal state of this buffer allocator.
};

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

                        // ---------------------
                        // class BufferAllocator
                        // ---------------------

// CREATORS
inline
BufferAllocator::BufferAllocator(char          *buffer,
                                 size_type      bufSize,
                                 AllocCallback  allocCallback)
: d_strategy(MAXIMUM_ALIGNMENT)
, d_cursor(0)
, d_buffer_p(buffer)
, d_bufferSize(static_cast<int>(bufSize))
, d_allocCallback(allocCallback)
{
}

inline
BufferAllocator::BufferAllocator(char              *buffer,
                                 size_type          bufSize,
                                 AlignmentStrategy  strategy,
                                 AllocCallback      allocCallback)
: d_strategy(strategy)
, d_cursor(0)
, d_buffer_p(buffer)
, d_bufferSize(static_cast<int>(bufSize))
, d_allocCallback(allocCallback)
{
}

// MANIPULATORS
inline
void BufferAllocator::deallocate(void *)
{
}

}  // close package namespace

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

typedef bslma::BufferAllocator bslma_BufferAllocator;
    // 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 ----------------------------------