// bslma_newdeleteallocator.h                                         -*-C++-*-
#ifndef INCLUDED_BSLMA_NEWDELETEALLOCATOR
#define INCLUDED_BSLMA_NEWDELETEALLOCATOR

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

//@PURPOSE: Provide singleton new/delete adaptor to 'bslma::Allocator' protocol.
//
//@CLASSES:
//  bslma::NewDeleteAllocator: support new/delete-style allocation/deallocation
//
//@SEE_ALSO: bslma_default, bslma_testallocator
//
//@DESCRIPTION: This component provides a concrete allocation mechanism,
// 'bslma::NewDeleteAllocator', that implements the 'bslma::Allocator' protocol
// to provide direct access to the system-supplied (native) global
// 'operator new' and 'operator delete' functions via that pure abstract
// interface.
//..
//   ,-------------------------.
//  ( bslma::NewDeleteAllocator )
//   `-------------------------'
//               |         allocator
//               |         singleton
//               |         ctor/dtor
//               V
//       ,----------------.
//      ( bslma::Allocator )
//       `----------------'
//                       allocate
//                       deallocate
//..
// The essential purpose of this component is to facilitate the default use of
// global 'new' and 'delete' in all components that accept a user-supplied
// allocator derived from 'bslma::Allocator' (see 'bslma_default').  Hence, the
// global 'operator new' and 'operator delete' functions are wrapped within
// concrete methods of a derived 'bslma::NewDeleteAllocator' class.  A 'static'
// (factory) method of 'bslma::NewDeleteAllocator' can be used to obtain a
// unique (singleton) 'bslma::NewDeleteAllocator' object for the given process,
// and whose lifetime is guaranteed to exceed any possibility of its use.  Note
// that the standard also requires the global 'operator new' to return
// maximally-aligned memory, which is a stricter post condition than the
// natural-alignment requirement imposed by the base-class contract, or than is
// provided by many other concrete implementations.
//
///Thread Safety
///-------------
// This class is fully thread-safe, which means that all non-creator object
// methods can be safely accessed concurrently (from multiple treads).  The
// singleton 'bslma::NewDeleteAllocator' can also be safely created/accessed
// concurrently (from multiple threads) via either the 'static' 'singleton' or
// 'allocator' (factory) methods.  Moreover, the underlying (native)
// implementation of 'new' and 'delete' are required by the C++ standard to
// ensure that concurrent access to either the virtual 'allocate' and/or
// 'deallocate' are also safe (i.e., will not not result in heap corruption).
// Note that this allocator therefore has stronger thread-safety guarantees
// than is required by the base-class contract or than is provided by many
// other derived concrete allocators.
//
///Usage
///-----
// The most common and proper use of 'bslma::NewDeleteAllocator' is both
// *indirect* and *by* *default* (see 'bslma_default').  For example, consider
// (along with its destructor) the default and copy constructors for, say, a
// simple container, such as 'my_ShortArray', each of which take as its final
// optional argument the address of a 'bslma::Allocator' protocol:
//..
//  // my_shortarray.h:
//  // ...
//  namespace bslma { class Allocator; }
//
//  class my_ShortArray {
//      short            *d_array_p;     // dynamically-allocated array
//      int               d_capacity;    // physical capacity (in elements)
//      int               d_length;      // logical length (in elements)
//      bslma::Allocator *d_allocator_p; // memory allocator (not owned)
//
//    public:
//      my_ShortArray(bslma::Allocator *basicAllocator = 0);
//          // Create an empty 'my_shortArray'.  Optionally specify a
//          // 'basicAllocator' used to supply memory.  If 'basicAllocator'
//          // is 0, the currently installed default allocator is used.
//
//      my_ShortArray(const my_ShortArray&  other,
//                    bslma::Allocator     *basicAllocator = 0);
//          // Create a 'bslma::ShortArray' having the same value as the
//          // specified 'other' array.  Optionally specify a 'basicAllocator'
//          // used to supply memory.  If 'basicAllocator' is 0, the currently
//          // installed default allocator is used.
//
//      ~my_ShortArray();
//          // Destroy this object.
//
//     // ...
//  };
//
//  // ...
//..
// In order to satisfy this contract, we will need a globally accessible
// utility (see 'bslma_default'), which by default returns the singleton
// 'bslma::NewDeleteAllocator', but which could be configured to return some
// other allocator, say a *test* allocator (see 'bslma_testallocator'):
//..
//  // my_default.h:
//  // ...
//  namespace bslma { class Allocator; }
//
//  struct my_Default {
//      // This class maintains a process-wide 'bslma::Allocator' object
//      // to be used when an allocator is needed, and not suppled explicitly.
//      // By default, the currently installed default allocator is the unique
//      // 'bslma::NewDeleteAllocator' object returned by the 'static' method,
//      // 'bslma::NewDeleteAllocator::singleton()'.  Note that the default
//      // allocator will exist longer than any possibility of its use.
//
//      static bslma::Allocator *allocator(bslma::Allocator *basicAllocator);
//          // Return the address of the specified modifiable
//          // 'basicAllocator' or, if 'basicAllocator' is 0, an instance of
//          // the currently installed default 'bslma::Allocator' object, which
//          // will exist longer than any possibility of its use.  Note
//          // that this function can safely be called concurrently (from
//          // multiple threads).
//
//      static bslma::Allocator *replace(bslma::Allocator *basicAllocator);
//          // Replace the address of the currently installed allocator with
//          // that of the specified modifiable 'basicAllocator' (or if 0,
//          // with the "factory" default, 'bslma::NewDeleteAllocator'), and
//          // return the address of the previous allocator.  The behavior is
//          // undefined unless 'basicAllocator' will exist longer than any
//          // possibility of its use.  Note that this function is *not* *at*
//          // *all* thread-safe, and should *never* be called when multiple
//          // threads are active.
//  };
//
//  // my_default.cpp:
//  // ...
//
//  #include <my_default.h>
//
//  static bslma::Allocator *s_default_p = 0; // load-time initialized
//
//  bslma::Allocator *my_Default::allocator(bslma::Allocator *basicAllocator)
//  {
//      return bslma::NewDeleteAllocator::allocator(s_default_p);
//  }
//
//  bslma::Allocator *my_Default::replace(bslma::Allocator *basicAllocator)
//  {
//      bslma::Allocator *tmp =
//                           bslma::NewDeleteAllocator::allocator(s_default_p);
//      s_default_p = bslma::NewDeleteAllocator::allocator(basicAllocator);
//      return tmp;
//  }
//..
// Notice that the only part of the 'bslma::NewDeleteAllocator' class we used
// directly was its static 'allocator' method, which -- in addition to safely
// constructing the singleton 'bslma::NewDeleteAllocator' object on first
// access -- also automatically replaces a 0 address value with that of
// singleton 'bslma::NewDeleteAllocator' object.  From now on, we will never
// again need to invoke the 'bslma_newdeleteallocator' component's interface
// directly, but instead use it through 'my_Default' (see 'bslma::Default' for
// what is actually used in practice).
//
// Turning back to our 'my_shortarray' example, let's now implement the two
// constructors using the 'bslma_newdeleteallocator' component indirectly via
// the 'my_default' component:
//..
//  // my_shortarray.cpp:
//  #include <my_shortarray.h>
//  #include <my_default.h>
//  #include <bsls_assert.h>
//
//  // ...
//
//  enum {
//      INITIAL_CAPACITY = 0, // recommended to avoid unnecessary allocations
//                            // possibly resulting in locking and extra thread
//                            // contention for the 'bslma::NewDeleteAllocator'
//
//      GROW_FACTOR = 2       // typical value for geometric growth
//  };
//
//  // ...
//
//  my_ShortArray::my_ShortArray(bslma::Allocator *basicAllocator)
//  : d_capacity(INITIAL_CAPACITY)
//  , d_length(0)
//  , d_allocator_p(my_Default::allocator(basicAllocator))
//  {
//      assert(d_allocator_p);
//      d_array_p = (short *)  // no thread contention if 'd_capacity' is 0
//                  d_allocator_p->allocate(d_capacity * sizeof *d_array_p);
//      assert(0 == d_array_p);
//  }
//
//  my_ShortArray::my_ShortArray(const my_ShortArray&   other,
//                               bslma::Allocator      *basicAllocator)
//  : d_capacity(other.d_capacity)
//  , d_length(other.d_length)
//  , d_allocator_p(my_Default::allocator(basicAllocator))
//  {
//      assert(d_allocator_p);
//      d_array_p = (short *)
//                  d_allocator_p->allocate(d_capacity * sizeof *d_array_p);
//      assert(!d_capacity == !d_array_p);
//      memcpy(d_array_p, other.d_array_p, d_length * sizeof *d_array_p);
//  }
//
//  my_ShortArray::~my_ShortArray()
//  {
//      d_allocator_p->deallocate(d_array_p); // no locking if 'd_array_p' is 0
//  }
//
// // ...
//..
// When the default constructor is called, the default capacity and length are
// recorded in data members via the initialization list.  The static function
// 'allocator' (provided in 'my_Default') is used to assign the value of the
// 'basicAllocator' address passed in, or if that is 0, the address of the
// currently installed default allocator, which by default is the singleton
// object of type 'bslma::NewDeleteAllocator', defined in this component.  Note
// that since 'INITIAL_CAPACITY' is 0, a default constructed object that is
// created using a 'bslma::NewDeleteAllocator' will *not* invoke the
// 'operator new' function, which on some platforms may needlessly acquire a
// lock, causing unnecessary overhead (the same potential overhead is avoided
// for 'operator delete' whenever a 0 'd_array_p' value is deallocated in the
// destructor) and 'd_allocator_p' refers to a 'bslma::NewDeleteAllocator'.
// Note also that, for the copy constructor, the currently installed default
// allocator, and not the 'other' array's allocator is used whenever
// 'basicAllocator' is 0 or not explicitly supplied.
//
// Finally note that this entire component is *not* intended for direct use by
// typical clients: See 'bslma_default' for more information or proper usage.

#include <bslscm_version.h>

#include <bslma_allocator.h>

namespace BloombergLP {

namespace bslma {

                        // ========================
                        // class NewDeleteAllocator
                        // ========================

class NewDeleteAllocator : public Allocator {
    // This class defines a concrete mechanism that adapts the system-supplied
    // (native) global 'operator new' and 'operator delete' to the 'Allocator'
    // protocol.  The class method 'singleton' returns a process-wide unique
    // object of this class whose lifetime is guaranteed to extend from the
    // first call to 'singleton' until the program terminates.  A second class
    // method, 'allocator', allows for conveniently replacing a "null"
    // allocator with this singleton object.  Note that this entire class
    // should generally not be used directly by typical clients (see
    // 'bslma_default' for more information).

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

  public:
    // CLASS METHODS
    static NewDeleteAllocator& singleton();
        // Return a reference to a process-wide unique object of this class.
        // The lifetime of this object is guaranteed to extend from the first
        // call of this method until the program terminates.  Note that this
        // method should generally not be used directly by typical clients (see
        // 'bslma_default' for more information).

    static Allocator *allocator(Allocator *basicAllocator);
        // Return the address of the specified modifiable 'basicAllocator' or,
        // if 'basicAllocator' is 0, the process-wide unique (see 'singleton')
        // object of this class.  Note that the behavior of this function is
        // equivalent to the following expression:
        //..
        //  basicAllocator
        //  ? basicAllocator
        //  : &NewDeleteAllocator::singleton()
        //..
        // Also note that if a 'NewDeleteAllocator' object is supplied, it is
        // owned by the class and must NOT be deleted.  Finally note that this
        // method should generally not be called directly by typical clients
        // (see 'bslma_default' for more information).

    // CREATORS
    NewDeleteAllocator();
        // Create a ("stateless") new-delete-allocator object that wraps the
        // global native 'operator new' and 'operator delete' functions in
        // order to supply memory via the 'Allocator' protocol.  Note that all
        // objects of this class share the same underlying resource; hence,
        // this constructor should generally not be invoked directly by
        // clients; instead, consider using the 'static' 'singleton' or
        // 'allocator' (factory) methods, or -- better -- the appropriate ones
        // in 'Default' (see 'bslma_default' for more information).

    virtual ~NewDeleteAllocator();
        // Destroy this allocator object.  Note that destroying this allocator
        // has no effect on any outstanding allocated memory.

    // MANIPULATORS
    virtual 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.  The alignment of the address
        // returned is the maximum alignment for any fundamental, pointer, or
        // enumerated type defined for this platform.  The behavior is
        // undefined unless '0 <= size'.  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 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.  Note that
        // global 'operator delete' is *not* called when 'address' is 0 (in
        // order to avoid having to acquire a lock, and potential contention in
        // multi-threaded programs).
};

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

                        // ------------------------
                        // class NewDeleteAllocator
                        // ------------------------

// CLASS METHODS
inline
Allocator *NewDeleteAllocator::allocator(Allocator *basicAllocator)
{
    return basicAllocator ? basicAllocator : &singleton();
}

// CREATORS
inline
NewDeleteAllocator::NewDeleteAllocator()
{
}

// MANIPULATORS
inline
void NewDeleteAllocator::deallocate(void *address)
{
    // While the C++ standard guarantees that calling delete(0) is safe
    // (3.7.3.2 paragraph 3), some libc implementations take out a lock to deal
    // with the free(0) case, so this check can improve efficiency of threaded
    // programs.

    if (address) {
        ::operator delete(address);
    }
}

}  // close package namespace

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

typedef bslma::NewDeleteAllocator bslma_NewDeleteAllocator;
    // 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 ----------------------------------