// bslma_deallocatorproctor.h                                         -*-C++-*-
#ifndef INCLUDED_BSLMA_DEALLOCATORPROCTOR
#define INCLUDED_BSLMA_DEALLOCATORPROCTOR

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

//@PURPOSE: Provide a proctor to conditionally manage a block memory.
//
//@CLASSES:
//  bslma::DeallocatorProctor: proctor to conditionally manage a memory
//
//@DEPRECATED: Use bslma_deallocatebytesproctor instead
//
//@SEE_ALSO: bslma_deallocatorguard, bslma_autodeallocator
//
//@DESCRIPTION: This component provides a proctor class template,
// `bslma::DeallocatorProctor`, to conditionally manage a block of
// (otherwise-unmanaged) memory.  If not explicitly released, the managed
// memory is deallocated automatically when the proctor object goes out of
// scope by freeing the memory using the parameterized `ALLOCATOR` (allocator
// or pool) supplied at construction.  Note that after a proctor object
// releases its managed memory, the same proctor can be reused to conditionally
// manage another block of memory (allocated from the same allocator or pool
// that was supplied at construction) by invoking the `reset` method.
//
///Requirement
///-----------
// The parameterized `ALLOCATOR` type of the `bslma::DeallocatorProctor` class
// must provide a (possibly `virtual`) method:
// ```
// void deallocate(void *address);
// ```
// to deallocate memory at the specified `address` (originally supplied by the
// `ALLOCATOR` object).
//
///Usage
///-----
// The `bslma::DeallocatorProctor` is normally used to achieve *exception*
// *safety* in an *exception* *neutral* way by managing memory in a sequence of
// continuous memory allocations.  Since each memory allocation may
// potentially throw an exception, an object of this proctor class can be used
// to (temporarily) manage newly allocated memory while attempting to allocate
// additional memory.  Should an exception occur in subsequent memory
// allocation, the proctor's destructor deallocates its managed memory,
// preventing a memory leak.
//
// This example illustrate a typical use of `bslma::DeallocatorProctor`.
// Suppose we have an array class that stores an "in-place" representation of
// objects of parameterized `TYPE`:
// ```
// // my_array.h
// // ...
//
// /// This class implements an "in-place" array of objects of
// /// parameterized `TYPE` stored contiguously in memory.
// template <class TYPE>
// class my_Array {
//
//     // DATA
//     TYPE             *d_array_p;      // dynamically allocated array
//     int               d_length;       // logical length of this array
//     int               d_size;         // physical capacity of this array
//     bslma::Allocator *d_allocator_p;  // allocator (held, not owned)
//
//   public:
//     // CREATORS
//
//     /// Create a `my_Array` object.  Optionally specify a
//     /// `basicAllocator` used to supply memory.  If `basicAllocator` is
//     /// 0, the currently installed default allocator is used.
//     my_Array(bslma::Allocator *basicAllocator = 0);
//
//     // ...
//
//     /// Destroy this `my_Array` object and all elements currently
//     /// stored.
//     ~my_Array();
//
//     // MANIPULATORS
//     // ...
//
//     /// Append (a copy of) the specified `object` of parameterized
//     /// `TYPE` to (the end of) this array.
//     void append(const TYPE& object);
//
//     // ...
// };
// ```
// Note that the rest of the `my_Array` interface (above) and implementation
// (below) is elided as the portion shown is sufficient to demonstrate the use
// of `bslma::DeallocatorProctor`.
// ```
// // CREATORS
// template <class TYPE>
// inline
// my_Array<TYPE>::my_Array(bslma::Allocator *basicAllocator)
// : d_length(0)
// , d_size(1)
// , d_allocator_p(bslma::Default::allocator(basicAllocator))
// {
//     d_array_p = (TYPE *)d_allocator_p->allocate(sizeof(TYPE));
// }
//
// template <class TYPE>
// my_Array<TYPE>::~my_Array()
// {
//     for (int i = 0; i < d_length; ++i) {
//         d_array_p[i].~TYPE();
//     }
//     d_allocator_p->deallocate(d_array_p);
// }
// ```
// In order to implement the `append` function, we first have to introduce an
// `my_AutoDestructor` `class`, which automatically destroy a sequence of
// managed objects upon destruction.  See `bslma::AutoDestructor` for a similar
// component with full documentation:
// ```
// // my_autodestructor.h
// // ...
//
// /// This class implements a range proctor that, unless its `release`
// /// method has previously been invoked, automatically invokes the
// /// destructor of each of sequence of objects it manages.
// template <class TYPE>
// class my_AutoDestructor {
//
//     // DATA
//     TYPE * d_origin_p;
//     int    d_length;
//
//   public:
//     // CREATORS
//
//     /// Create an `my_AutoDestructor` to manage a contiguous sequence of
//     /// objects.
//     my_AutoDestructor(TYPE *origin, int length)
//     : d_origin_p(origin)
//     , d_length(length)
//     {
//     }
//
//     /// Destroy this `my_AutoDestructor` and, unless its `release`
//     /// method has previously been invoked, destroy the sequence of
//     /// objects it manages by invoking the destructor of each of the
//     /// (managed) objects.
//     ~my_AutoDestructor()
//     {
//         if (d_length) {
//             for (; d_length > 0; --d_length, ++d_origin_p) {
//                 d_origin_p->~TYPE();
//             }
//         }
//     }
//
//     // MANIPULATORS
//
//     /// Increase by one the length of the sequence of objects managed by
//     /// this range proctor.
//     my_AutoDestructor<TYPE>& operator++()
//     {
//         ++d_length;
//         return *this;
//     }
//
//     /// Release from management the sequence of objects currently
//     /// managed by this range proctor.
//     void release()
//     {
//         d_length = 0;
//     }
// };
// ```
// We can now continue with our implementation of the `my_Array` class:
// ```
// // my_array.h
// // ...
//
// // MANIPULATORS
// template <class TYPE>
// void my_Array<TYPE>::append(const TYPE &object)
// {
//     if (d_length == d_size) {
//         TYPE *newArray = (TYPE *)d_allocator_p->allocate(
//                              d_size * 2 * sizeof(TYPE));  // possibly throw
//
//         //*****************************************************************
//         // Note the use of the deallocator proctor on 'newArray' (below). *
//         //*****************************************************************
//
//         bslma::DeallocatorProctor<bslma::Allocator> proctor(newArray,
//                                                             d_allocator_p);
//
//         // Note use of 'my_AutoDestructor' here to protect the copy
//         // construction of 'TYPE' objects.
//         my_AutoDestructor<TYPE> destructor(newArray, 0);
//
//         for (int i = 0; i < d_length; ++i) {
//             new(&newArray[i]) TYPE(d_array_p[i], d_allocator_p);
//                                                          // possibly throw
//             d_array_p[i].~TYPE();
//             ++destructor;
//         }
//
//         destructor.release();
//
//         //*********************************************************
//         // Note that the deallocator proctor is released (below). *
//         //*********************************************************
//
//         proctor.release();
//
//         d_allocator_p->deallocate(d_array_p);
//         d_array_p = newArray;
//         d_size   *= 2;
//     }
//
//     new(&d_array_p[d_length]) TYPE(object, d_allocator_p);
//     ++d_length;
// }
// ```
// Both the use of `bslma::DeallocatorProctor` and `my_AutoDestructor` are
// necessary to implement exception safety.
//
// The `append` method defined above potentially throws in two places.  If the
// memory allocator held in `d_allocator_p` where to throw while attempting to
// allocate the new array of parameterized `TYPE`, no memory would be leaked.
// But without subsequent use of the `bslma::DeallocatorProctor`, if the
// allocator subsequently throws while copy constructing the objects from the
// old array to the new array, the newly allocated memory block would be
// leaked.  Using the `bslma::DeallocatorProctor` prevents the leak by
// deallocating the proctored memory automatically should the proctor go out
// of scope before the `release` method of the proctor is called (such as when
// the function exits prematurely due to an exception).
//
// Similarly, any resources acquired as a result of copy constructing the
// objects from the old array to the new array would be leaked if the
// constructor of `TYPE` throws.  Using the `my_AutoDestructor` prevents the
// leak by invoking the destructor of the proctored (and newly created) objects
// in the new array should the `my_AutoDestructor` goes out of scope before the
// `release` method of the proctor is called.
//
// Note that the `append` method assumes the copy constructor of `TYPE` takes
// an allocator as a second argument.  In production code, a constructor proxy
// that checks the traits of `TYPE` (to see whether `TYPE` uses
// `bslma::Allocator`) should be used (see `bslalg::ConstructorProxy`).

#include <bslscm_version.h>

#include <bslma_deallocatebytesproctor.h>

#include <bsls_assert.h>

namespace BloombergLP {

namespace bslma {

                        // ========================
                        // class DeallocatorProctor
                        // ========================

/// This class implements a proctor that, unless its `release` method has
/// previously been invoked, automatically deallocates a block of managed
/// memory upon destruction by invoking the `deallocate` method of an
/// allocator (or pool) of parameterized `ALLOCATOR` type supplied to it at
/// construction.  The managed memory must have been provided by this
/// allocator (or pool), which must remain valid throughout the lifetime of
/// the proctor object.
template <class ALLOCATOR>
class DeallocatorProctor {

    // DATA
    DeallocateBytesProctor<ALLOCATOR *> d_imp;

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

  public:
    // CREATORS

    /// Create a deallocator proctor that conditionally manages the
    /// specified `memory` (if non-zero), and that uses the specified
    /// `allocator` to deallocate the block of memory managed by this
    /// proctor (if not released -- see `release`) upon destruction.  The
    /// behavior is undefined unless `allocator` is non-zero and supplied
    /// `memory`.  Note that `allocator` must remain valid throughout the
    /// lifetime of this proctor.
    DeallocatorProctor(void *memory, ALLOCATOR *allocator);

    /// Destroy this deallocator proctor, and deallocate the block of memory
    /// it manages (if any) by invoking the `deallocate` method of the
    /// allocator (or pool) that was supplied at construction of this
    /// proctor.  If no memory is currently being managed, this method has
    /// no effect.
    ~DeallocatorProctor();

    // MANIPULATORS

    /// Release from management the block of memory currently managed by
    /// this proctor.  If no memory is currently being managed, this method
    /// has no effect.
    void release();

    /// Set the specified `memory` as the block of memory to be managed by
    /// this proctor.  The behavior is undefined unless `memory` is non-zero
    /// and was allocated by the allocator (or pool) supplied at
    /// construction.  Note that this method releases any previously-managed
    /// memory from management (without deallocating it), and so may be
    /// invoked with or without having called `release` when reusing this
    /// object.
    void reset(void *memory);
};

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

                        // ------------------------
                        // class DeallocatorProctor
                        // ------------------------

// CREATORS
template <class ALLOCATOR>
inline
DeallocatorProctor<ALLOCATOR>::DeallocatorProctor(void      *memory,
                                                  ALLOCATOR *allocator)
    : d_imp(allocator, memory, 1)
{
    BSLS_ASSERT_SAFE(allocator);
}

template <class ALLOCATOR>
inline
DeallocatorProctor<ALLOCATOR>::~DeallocatorProctor()
{
}

// MANIPULATORS
template <class ALLOCATOR>
inline
void DeallocatorProctor<ALLOCATOR>::release()
{
    d_imp.release();
}

template <class ALLOCATOR>
inline
void DeallocatorProctor<ALLOCATOR>::reset(void *memory)
{
    BSLS_ASSERT_SAFE(memory);

    d_imp.reset(memory, 1);
}

}  // close package namespace

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

#ifdef bslma_DeallocatorProctor
#undef bslma_DeallocatorProctor
#endif
/// This alias is defined for backward compatibility.
#define bslma_DeallocatorProctor bslma::DeallocatorProctor
#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 ----------------------------------
