// bslma_destructorproctor.h                                          -*-C++-*-
#ifndef INCLUDED_BSLMA_DESTRUCTORPROCTOR
#define INCLUDED_BSLMA_DESTRUCTORPROCTOR

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

//@PURPOSE: Provide a proctor to conditionally manage an object.
//
//@CLASSES:
//  bslma::DestructorProctor: proctor to conditionally manage an object
//
//@SEE_ALSO: bslma_destructorguard, bslma_autodestructor
//
//@DESCRIPTION: This component provides a proctor class template,
// `bslma::DestructorProctor`, to conditionally manage an (otherwise-unmanaged)
// object of parameterized `TYPE` supplied at construction.  If not explicitly
// released, the managed object is destroyed automatically when the proctor
// object goes out of scope by calling the object's destructor.  Note that
// after a proctor object releases its managed object, the same proctor can be
// reused to conditionally manage another object by invoking the `reset`
// method.
//
///Usage
///-----
// The `bslma::DestructorProctor` is normally used to manage objects that are
// constructed sequentially in a block of memory provided.  This is often the
// case when memory management and primitive helpers are implemented in
// different components.  An example would be the construction of a pair object
// within another container with the help of a scalar primitive helper (see
// `bslma_constructionutil`).  After the first object is constructed in the
// provided memory, it should be protected in case the constructor of the
// second object throws.  The following example illustrates a typical use of
// the `bslma::DestructorProctor`.
//
// First, suppose we have a pair class similar to `std::pair`:
// ```
// // MyPair.h
// // ...
//
// /// This class provides a pair container to pair two different objects,
// /// one of parameterized `TYPE1`, and the other of parameterized
// /// `TYPE2`.
// template <class TYPE1, class TYPE2>
// class MyPair {
//
//   public:
//     // PUBLIC TYPES
//     typedef TYPE1 firstType;
//     typedef TYPE2 secondType;
//
//     // PUBLIC DATA
//     TYPE1            first;          // first object
//     TYPE2            second;         // second object
//
//     // Declare trait `my_PairTrait`.
//     // ...
//
//   public:
//     // CREATORS
//     // ...
//
//     /// Create a `MyPair` object that holds a copy of the specified
//     /// `iFirst` and `iSecond`.  Optionally specify `basicAllocator` to
//     /// supply memory.  If `basicAllocator` is zero,  the global default
//     /// allocator will be used to supply memory.
//     MyPair(const TYPE1&      iFirst,
//            const TYPE2&      iSecond,
//            bslma::Allocator *basic_Allocator = 0)
//     : first(iFirst)
//     , second(iSecond)
//     , d_allocator_p(bslma::Default::allocator(basic_Allocator))
//     {
//     }
//
//     // ...
//
// };
// ```
// Note that parts of the implementation, including the `my_PairTrait`
// declaration, are elided.  The `my_PairTrait` will be used by the primitive
// helper to customize implementations for objects that are pairs.
//
// We now implement the primitive helper:
// ```
// // MyPrimitives.h
// // ...
//
// /// This `struct` provides a namespace for primitive functions used to
// /// construct, destroy, insert, append and remove objects.
// struct MyPrimitives {
//
//   private:
//     // PRIVATE TYPES
//     enum { PAIR_TRAIT = 1, NIL_TRAIT = 0 };
//
//   public:
//     // CLASS METHODS
//
//     /// Copy construct the specified `original` into the specified
//     /// `address` using the specified `basicAllocator` (if the
//     /// copy constructor of `TYPE` takes an allocator).
//     template <class TYPE>
//     static void copyConstruct(TYPE             *address,
//                               const TYPE&       original,
//                               bslma::Allocator *basicAllocator);
//
//     /// Copy construct the specified `original` into the specified
//     /// `address` using the specified `basicAllocator` (if the
//     /// copy constructor of `TYPE` takes an allocator).  Note that
//     /// the last parameter is used only for overload resolution.
//     template <class TYPE>
//     static void copyConstruct(TYPE             *address,
//                               const TYPE&       original,
//                               bslma::Allocator *basicAllocator,
//                               bsl::integral_constant<bool, PAIR_TRAIT> *);
//
//     /// Copy construct the specified `original` into the specified
//     /// `address` using the specified `basicAllocator` (if the
//     /// copy constructor of `TYPE` takes an allocator).  Note that
//     /// the last parameter is used only for overload resolution.
//     template <class TYPE>
//     static void copyConstruct(TYPE             *address,
//                               const TYPE&       original,
//                               bslma::Allocator *basicAllocator,
//                               bsl::integral_constant<bool, NIL_TRAIT> *);
// };
//
// template <class TYPE>
// inline
// void MyPrimitives::copyConstruct(TYPE             *address,
//                                  const TYPE&       original,
//                                  bslma::Allocator *basicAllocator)
// {
//     copyConstruct(address,
//                   original,
//                   basicAllocator,
//                   (typename my_HasPairTrait<TYPE>::type *)0);
// }
// ```
// The implementation of `copyConstruct` constructs the pair object in two
// steps because of the use of allocators.  We cannot simply pass the allocator
// to the copy constructor of the pair object (since `std::pair` does not take
// an allocator).  Therefore, we copy construct `first` and `second` directly
// in the pair object.
// ```
// template <class TYPE>
// inline
// void MyPrimitives::copyConstruct(TYPE             *address,
//                                  const TYPE&       original,
//                                  bslma::Allocator *basicAllocator,
//                                  bsl::integral_constant<int, PAIR_TRAIT> *)
// {
//     copyConstruct(&address->first, original.first, basicAllocator);
//
//     //**************************************************
//     // Note the use of the destructor proctor (below). *
//     //**************************************************
//
//     bslma::DestructorProctor<typename TYPE::firstType> proctor(
//                                                           &address->first);
//
//     copyConstruct(&address->second, original.second, basicAllocator);
//
//     //********************************************************
//     // Note that the destructor proctor is released (below). *
//     //********************************************************
//
//     proctor.release();
// }
//
// template <class TYPE>
// inline
// void MyPrimitives::copyConstruct(TYPE             *address,
//                                  const TYPE&       original,
//                                  bslma::Allocator *basicAllocator,
//                                  bsl::integral_constant<int, NIL_TRAIT> *)
// {
//     new(address)TYPE(original, basicAllocator);
// }
// ```
// Note that the implementation of `my_HasPairTrait` is not shown.  It is used
// to detect whether `TYPE` has `my_PairTrait` or not (see `bslalg_typetraits`,
// `bslalg_typetraitpair`).
//
// In the above implementation, if the copy construction of the second object
// in the pair throws, all memory (and any other resources) acquired as a
// result of copying the (not-yet-managed) object would be leaked.  Using the
// `bslma::DestructorProctor` prevents the leaks by invoking the destructor of
// the proctored object 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).
//
// Note that the `copyConstruct` method assumes the copy constructor of
// `TYPE::firstType` and `TYPE::secondType` takes an allocator as a second
// argument.  In production code, a constructor proxy that checks the traits of
// `TYPE::firstType` and `TYPE::secondType` (to determine whether they uses
// `bslma::Allocator`) should be used (see `bslalg_constructorproxy`).

#include <bslscm_version.h>

#include <bslma_destructionutil.h>

#include <bsls_assert.h>
#include <bsls_performancehint.h>

namespace BloombergLP {

namespace bslma {

                        // =======================
                        // class DestructorProctor
                        // =======================

/// This class implements a proctor that, unless its `release` method has
/// previously been invoked, automatically destroys a managed object upon
/// destruction by invoking the (managed) object's destructor.
template <class TYPE>
class DestructorProctor {

    // DATA
    TYPE *d_object_p;  // managed object

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

  public:
    // CREATORS

    /// Create a destructor proctor that conditionally manages the specified
    /// `object` (if non-zero) by invoking the destructor of the object
    /// managed by this proctor (if not released -- see `release`) upon
    /// destruction.
    explicit DestructorProctor(TYPE *object);

    /// Destroy this destructor proctor, and destroy the object it manages
    /// (if any) by invoking the destructor of the (managed) object.  If no
    /// object is currently being managed, this method has no effect.
    ~DestructorProctor();

    // MANIPULATORS

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

    /// Set the specified `object` as the object to be managed by this
    /// proctor.  The behavior is undefined unless `object` is non-zero.
    /// Note that this method releases any previously-managed object from
    /// management (without destroying it), and so may be invoked with or
    /// without having called `release` when reusing this object.
    void reset(TYPE *object);
};

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

                        // -----------------------
                        // class DestructorProctor
                        // -----------------------

// CREATORS
template <class TYPE>
inline
DestructorProctor<TYPE>::DestructorProctor(TYPE *object)
: d_object_p(object)
{
}

template <class TYPE>
inline
DestructorProctor<TYPE>::~DestructorProctor()
{
    if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 != d_object_p)) {
        DestructionUtil::destroy(d_object_p);
    }
}

// MANIPULATORS
template <class TYPE>
inline
void DestructorProctor<TYPE>::release()
{
    d_object_p = 0;
}

template <class TYPE>
inline
void DestructorProctor<TYPE>::reset(TYPE *object)
{
    BSLS_ASSERT_SAFE(object);

    d_object_p = object;
}

}  // close package namespace

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

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