// 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:
//..
//  double evaluatePassword(const char *password, bslma::Allocator *allocator);
//      // 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.
//..
// 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
                        // ======================

template <class ALLOCATOR>
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.

    // 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
    DeallocatorGuard(void *memory, ALLOCATOR *allocator);
        // 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();
        // 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.
};

// ============================================================================
//                          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
#define bslma_DeallocatorGuard bslma::DeallocatorGuard
    // 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 ----------------------------------