// bslma_testallocatorexception.h                                     -*-C++-*-
#ifndef INCLUDED_BSLMA_TESTALLOCATOREXCEPTION
#define INCLUDED_BSLMA_TESTALLOCATOREXCEPTION

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

//@PURPOSE: Provide an exception class for memory allocation operations.
//
//@CLASSES:
//  bslma::TestAllocatorException: exception containing allocation information
//
//@DESCRIPTION: This component defines a simple exception object for testing
// exceptions during memory allocation operations.  The exception object
// 'bslma::TestAllocatorException' contains information about the allocation
// request, which can be queried for by the "catcher" of this exception.
//
///Usage
///-----
// In the following example, the 'bslma::TestAllocatorException' object is
// thrown by the 'allocate' method of the 'my_Allocator' object after the
// number of allocation requests exceeds the allocator's allocation limit.
// This example demonstrates how to use a user-defined allocator (e.g.,
// 'my_Allocator') and 'bslma::TestAllocatorException' to verify that an object
// (e.g., 'my_ShortArray') under test is exception-neutral:
//..
//  // my_allocator.h
//  #include <bslma_allocator.h>
//
//  class my_Allocator : public bslma::Allocator {
//      int d_allocationLimit;
//      // ...
//
//    private:
//      // NOT IMPLEMENTED
//      my_Allocator(const my_Allocator&);
//      my_Allocator& operator=(const my_Allocator&);
//
//    public:
//      // CREATORS
//      my_Allocator() : d_allocationLimit(-1) {}
//      ~my_Allocator() {}
//
//      void *allocate(int size);
//      void deallocate(void *address) { free(address); }
//      void setAllocationLimit(int limit){ d_allocationLimit = limit; }
//      int allocationLimit() const { return d_allocationLimit; }
//      // ...
//  };
//
//  // my_allocator.cpp
//  #include <my_allocator.h>
//
//  void *my_Allocator::allocate(int size)
//  {
//  #ifdef BDE_BUILD_TARGET_EXC
//      if (0 <= d_allocationLimit) {
//          --d_allocationLimit;
//          if (0 > d_allocationLimit) {
//              throw bslma::TestAllocatorException(size);
//          }
//      }
//  #endif
//      return (void *)malloc(size);
//  }
//..
// Note that the macro 'BDE_BUILD_TARGET_EXC' is defined at compile-time to
// indicate whether exceptions are enabled.  In the above code, if exceptions
// are not enabled, the code that throws 'bslma::TestAllocatorException' is
// never executed.  The following is the test driver for 'my_ShortArray'.
//
// Note that "\$" must be replaced by "\" in the preprocessor macro definitions
// that follow.  The "$" symbols are present in this header file to avoid a
// diagnostic elicited by some compilers (e.g., "warning: multi-line comment").
//..
//  // my_shortarray.t.cpp
//  #include <my_shortarray.h>
//  #include <my_testallocator.h>
//  #include <bslma_testallocatorexception.h>
//
//  // ...
//
//  #ifdef BDE_BUILD_TARGET_EXC
//  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN {                       \$
//  {                                                                        \$
//      static int firstTime = 1;                                            \$
//      if (veryVerbose && firstTime) std::cout <<                           \$
//          "### BSLMA EXCEPTION TEST -- (ENABLED) --" << std::endl;         \$
//      firstTime = 0;                                                       \$
//  }                                                                        \$
//  if (veryVeryVerbose) std::cout <<                                        \$
//      "### Begin bslma exception test." << std::endl;                      \$
//  int bslmaExceptionCounter = 0;                                           \$
//  static int bslmaExceptionLimit = 100;                                    \$
//  testAllocator.setAllocationLimit(bslmaExceptionCounter);                 \$
//  do {                                                                     \$
//      try {
//
//  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END                           \$
//      } catch (bslma::TestAllocatorException& e) {                         \$
//          if (veryVerbose && bslmaExceptionLimit || veryVeryVerbose) {     \$
//              --bslmaExceptionLimit;                                       \$
//              std::cout << "(*** " << bslmaExceptionCounter << ')';        \$
//              if (veryVeryVerbose) { std::cout << " BSLMA_EXCEPTION: "     \$
//                  << "alloc limit = " << bslmaExceptionCounter << ", "     \$
//                  << "last alloc size = " << e.numBytes();                 \$
//              }                                                            \$
//              else if (0 == bslmaExceptionLimit) {                         \$
//                  std::cout << " [ Note: 'bslmaExceptionLimit' reached. ]";\$
//              }                                                            \$
//              std::cout << std::endl;                                      \$
//          }                                                                \$
//          testAllocator.setAllocationLimit(++bslmaExceptionCounter);       \$
//          continue;                                                        \$
//      }                                                                    \$
//      testAllocator.setAllocationLimit(-1);                                \$
//      break;                                                               \$
//  } while (1);                                                             \$
//  if (veryVeryVerbose) std::cout <<                                        \$
//      "### End bslma exception test." << std::endl;                        \$
//  }
//  #else
//  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN                         \$
//  {                                                                        \$
//      static int firstTime = 1;                                            \$
//      if (verbose && firstTime) { std::cout <<                             \$
//          "### BSLMA EXCEPTION TEST -- (NOT ENABLED) --" << std::endl;     \$
//          firstTime = 0;                                                   \$
//      }                                                                    \$
//  }
//  #define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
//  #endif
//
//  // ...
//
//  static
//  bool areEqual(const short *array1, const short *array2, int numElement)
//      // Return 'true' if the specified initial 'numElement' in the specified
//      // 'array1' and 'array2' have the same values, and 'false' otherwise.
//  {
//      for (int i = 0; i < numElement; ++i) {
//          if (array1[i] != array2[i]) return false;
//      }
//      return true;
//  }
//
//  int main(int argc, char *argv[]) {
//      int test = argc > 1 ? atoi(argv[1]) : 0;
//      int verbose = argc > 2;
//      int veryVerbose = argc > 3;
//      int veryVeryVerbose = argc > 4;
//
//      my_Allocator testAllocator;
//
//      switch (test) { case 0:
//
//        // ...
//
//        case 6: {
//          struct {
//              int d_line;
//              int d_numElem;
//              short d_exp[NUM_VALUES];
//          } DATA[] = {
//              { L_, 0, {} },
//              { L_, 1, { V0 } },
//              { L_, 5, { V0, V1, V2, V3, V4 } }
//          };
//
//          const int NUM_TEST = sizeof DATA / sizeof *DATA;
//
//          for (int ti = 0; ti < NUM_TEST; ++ti) {
//              const int    LINE     = DATA[ti].d_line;
//              const int    NUM_ELEM = DATA[ti].d_numElem;
//              const short *EXP      = DATA[ti].d_exp;
//
//              BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN {
//                  my_ShortArray mA(&testAllocator);
//                  const my_ShortArray& A = mA;
//                  for (int ei = 0; ei < NUM_ELEM; ++ei) {
//                      mA.append(VALUES[ei]);
//                  }
//                  if (veryVerbose) { P_(ti); P_(NUM_ELEM); P(A); }
//                  LOOP2_ASSERT(LINE, ti, areEqual(EXP, A, NUM_ELEM));
//              } BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
//          }
//
//          if (veryVerbose) std::cout << testAllocator << std::endl;
//        } break;
//
//        // ...
//
//      }
//
//      // ...
//  }
//..

#include <bslscm_version.h>

#include <bslma_allocator.h>

#include <bsls_exceptionutil.h>
#include <bsls_keyword.h>

#include <new>          // For 'std::bad_alloc'

namespace BloombergLP {

namespace bslma {

                        // ============================
                        // class TestAllocatorException
                        // ============================

class TestAllocatorException : public std::bad_alloc {
    // This class defines an exception object for memory allocation operations.
    // Objects of this class contain information about an allocation request.

  public:
    // PUBLIC TYPES
    typedef Allocator::size_type size_type;
        // Alias for the type used by the 'Allocator' protocol to request a
        // memory allocation of a given size.

  private:
    // DATA
    size_type d_numBytes;  // number of bytes requested in an allocation
                           // operation

  public:
    // CREATORS
    explicit TestAllocatorException(size_type numBytes);
        // Create an exception object initialized with the specified 'numBytes'
        // that indicates an allocation request size.

    //! ~TestAllocatorException();
        // Destroy this object.  Note that this method's definition is compiler
        // generated.

    // ACCESSORS
    size_type numBytes() const;
        // Return the number of bytes (supplied at construction) that indicates
        // an allocation request size.

    const char *what() const BSLS_EXCEPTION_VIRTUAL_NOTHROW
                                                         BSLS_KEYWORD_OVERRIDE;
        // Return a pointer to the string literal
        // "bslma::TestAllocatorException" having a storage duration of the
        // lifetime of the program.  Note that the caller should *not* attempt
        // to free this memory.
};

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

                        // ----------------------------
                        // class TestAllocatorException
                        // ----------------------------

// CREATORS
inline
TestAllocatorException::TestAllocatorException(size_type numBytes)
: d_numBytes(numBytes)
{
}

// ACCESSORS
inline
TestAllocatorException::size_type
TestAllocatorException::numBytes() const
{
    return d_numBytes;
}

inline
const char *
TestAllocatorException::what() const BSLS_EXCEPTION_VIRTUAL_NOTHROW
{
    return "bslma::TestAllocatorException";
}

}  // close package namespace

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

typedef bslma::TestAllocatorException bslma_TestAllocatorException;
    // 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 ----------------------------------