// bslma_deallocatorguard.h                                           -*-C++-*-
#ifndef INCLUDED_BSLMA_DEALLOCATORGUARD
#define INCLUDED_BSLMA_DEALLOCATORGUARD

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

//@PURPOSE: Provide a guard to unconditionally manage a block of memory.
//
//@CLASSES:
//  bslma::DeallocatorGuard: guard to unconditionally manage a block of memory
//
//@SEE_ALSO: bslma_deallocatorproctor, bslma_autodeallocator
//
//@DESCRIPTION: This component provides a guard class template,
// `bslma::DeallocatorGuard`, to unconditionally manage a block of
// (otherwise-unmanaged) memory.  The managed memory is deallocated
// automatically when the guard object goes out of scope using the `deallocate`
// method of the parameterized `ALLOCATOR` (allocator or pool) supplied at
// construction.
//
///Requirement
///-----------
// The parameterized `ALLOCATOR` type of the `bslma::DeallocatorGuard` class
// template must provide a (possibly `virtual`) method:
// ```
// void deallocate(void *address);
// ```
// to deallocate memory at the specified `address` (originally supplied by the
// `ALLOCATOR` object).
//
///Usage
///-----
// A `bslma::DeallocatorGuard` can be used to ensure that a dynamically
// allocated raw memory resource is safely deallocated in the presence of
// multiple return statements or exceptions in an exception-neutral way (i.e.,
// without the need for `try`/`catch` blocks).  In this simple example,
// consider the function `evaluatePassword` which attempts to determine how
// secure a given password might be:
// ```
// /// Evaluate the strength of the specified `password`, using the
// /// specified `allocator` to supply memory for evaluation.  Return a
// /// real value in the range `[ 0.0 .. 1.0 ]` where 0.0 indicates the
// /// weakest password, and 1.0 the strongest.
// double evaluatePassword(const char *password, bslma::Allocator *allocator);
// ```
// This function will be implemented in terms of three *exception* *neutral*
// subroutines, each of which operates on a writable copy of the
// null-terminated password, (perturbing its contents slightly) and requiring
// unbounded amounts of scratch memory (to be allocated and deallocated from a
// supplied allocator):
// ```
// int subroutine1(char *inOut, bslma::Allocator *allocator);
// int subroutine2(char *inOut, bslma::Allocator *allocator);
// int subroutine3(char *inOut, bslma::Allocator *allocator);
// ```
// A final subroutine is then used to determine and return the score:
// ```
// double finalSubroutine(const char *result);
// ```
// The top-level routine is implemented as follows:
// ```
// double evaluatePassword(const char *password, bslma::Allocator *allocator)
// {
//
//     // Set up local writable copy of password in buffer.
//
//     size_t size = strlen(password) + 1;
//     char *buffer = (char *)allocator->allocate(size);
//     memcpy(buffer, password, size);
//
//     //**************************************************************
//     //* Note the use of the deallocator guard on 'buffer' (below). *
//     //**************************************************************
//
//     bslma::DeallocatorGuard<bslma::Allocator> guard(buffer, allocator);
//
//     // Process and evaluate the supplied password.
//
//     if (0 != subroutine1(buffer, allocator)) {
//         return 0.0;                                               // RETURN
//     }
//     if (0 != subroutine2(buffer, allocator)) {
//         return 0.2;                                               // RETURN
//     }
//     if (0 != subroutine3(buffer, allocator)) {
//         return 0.4;                                               // RETURN
//     }
//
//     return finalSubroutine(buffer);
//
// }  // note that 'buffer' is deallocated at end of block regardless
// ```
// Notice that if any of the initial (numbered) subroutines returns a non-zero
// status value, the top-level `evaluatePassword` routine returns immediately
// with a predetermined score.  Moreover, each of these routines may encounter
// a `bad_alloc` exception should the supplied allocator fail to return the
// requested memory.  Even if all of these subroutines evaluates successfully,
// the score calculated using `finalEval` is returned directly by
// `evaluatePassword`, yet we still need to deallocate `buffer`.  By guarding
// buffer with a `bslma::DeallocatorGuard` as shown above, all of these issues
// are fully addressed, and the top-level routine is also *exception* *neutral*
// as desired.

#include <bslscm_version.h>

#include <bsls_assert.h>

namespace BloombergLP {

namespace bslma {

                        // ======================
                        // class DeallocatorGuard
                        // ======================

/// This class implements a guard that unconditionally 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 supplied by the
/// allocator (or pool), which must remain valid throughout the lifetime of
/// the guard object.
template <class ALLOCATOR>
class DeallocatorGuard {

    // DATA
    void      *d_memory_p;     // address of managed memory
    ALLOCATOR *d_allocator_p;  // allocator or pool (held, not owned)

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

  public:
    // CREATORS

    /// Create a deallocator guard that unconditionally manages the
    /// specified `memory` block, and that uses the specified `allocator` to
    /// deallocate `memory` upon destruction of this guard.  The behavior is
    /// undefined unless `memory` and `allocator` are non-zero, and
    /// `allocator` supplied `memory`.  Note that `allocator` must remain
    /// valid throughout the lifetime of this guard.
    DeallocatorGuard(void *memory, ALLOCATOR *allocator);

    /// Destroy this deallocator guard and deallocate the block of memory it
    /// manages by invoking the `deallocate` method of the allocator (or
    /// pool) that was supplied with the address of the (managed) memory at
    /// construction.
    ~DeallocatorGuard();
};

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

                        // ----------------------
                        // class DeallocatorGuard
                        // ----------------------

// CREATORS
template <class ALLOCATOR>
inline
DeallocatorGuard<ALLOCATOR>::DeallocatorGuard(void      *memory,
                                              ALLOCATOR *allocator)
: d_memory_p(memory)
, d_allocator_p(allocator)
{
    BSLS_ASSERT_SAFE(memory);
    BSLS_ASSERT_SAFE(allocator);
}

template <class ALLOCATOR>
inline
DeallocatorGuard<ALLOCATOR>::~DeallocatorGuard()
{
    BSLS_ASSERT_SAFE(d_memory_p);
    BSLS_ASSERT_SAFE(d_allocator_p);

    d_allocator_p->deallocate(d_memory_p);
}

}  // close package namespace

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

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