]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libstdc++-v3/include/ext/throw_allocator.h
Update copyright years in libstdc++-v3/
[thirdparty/gcc.git] / libstdc++-v3 / include / ext / throw_allocator.h
index 38f6afb33a8a2f96b32cd469ac4877b410314e83..30b6c47d503c9bd89ad9728c505afbd88cede675 100644 (file)
@@ -1,11 +1,11 @@
 // -*- C++ -*-
 
-// Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// Copyright (C) 2005-2014 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the terms
 // of the GNU General Public License as published by the Free Software
-// Foundation; either version 2, or (at your option) any later
+// Foundation; either version 3, or (at your option) any later
 // version.
 
 // This library is distributed in the hope that it will be useful, but
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 // General Public License for more details.
 
-// You should have received a copy of the GNU General Public License
-// along with this library; see the file COPYING.  If not, write to
-// the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
-// MA 02111-1307, USA.
-
-// As a special exception, you may use this file as part of a free
-// software library without restriction.  Specifically, if other files
-// instantiate templates or use macros or inline functions from this
-// file, or you compile this file and link it with other files to
-// produce an executable, this file does not by itself cause the
-// resulting executable to be covered by the GNU General Public
-// License.  This exception does not however invalidate any other
-// reasons why the executable file might be covered by the GNU General
-// Public License.
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
 
 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
 
 // purpose. It is provided "as is" without express or implied
 // warranty.
 
-/**
- * @file throw_allocator.h Contains an exception-throwing allocator
- * useful for testing exception safety. In addition, allocation
- * addresses are stored and sanity checked.
+/** @file ext/throw_allocator.h
+ *  This file is a GNU extension to the Standard C++ Library.
+ *
+ *  Contains two exception-generating types (throw_value, throw_allocator)
+ *  intended to be used as value and allocator types while testing
+ *  exception safety in templatized containers and algorithms. The
+ *  allocator has additional log and debug features. The exception
+ *  generated is of type forced_exception_error.
  */
 
 #ifndef _THROW_ALLOCATOR_H
 #define _THROW_ALLOCATOR_H 1
 
 #include <cmath>
+#include <ctime>
 #include <map>
-#include <set>
 #include <string>
 #include <ostream>
 #include <stdexcept>
 #include <utility>
-#include <tr1/random>
-
-_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
+#include <bits/functexcept.h>
+#include <bits/move.h>
+#if __cplusplus >= 201103L
+# include <functional>
+# include <random>
+#else
+# include <tr1/functional>
+# include <tr1/random>
+#endif
+
+namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+  /**
+   *  @brief Thown by exception safety machinery.
+   *  @ingroup exceptions
+   */
+  struct forced_error : public std::exception
+  { };
 
-  class twister_rand_gen
+  // Substitute for forced_error object when -fno-exceptions.
+  inline void
+  __throw_forced_error()
+  { _GLIBCXX_THROW_OR_ABORT(forced_error()); }
+
+  /**
+   *  @brief Base class for checking address and label information
+   *  about allocations. Create a std::map between the allocated
+   *  address (void*) and a datum for annotations, which are a pair of
+   *  numbers corresponding to label and allocated size.
+   */
+  struct annotate_base
   {
-  public:
-    twister_rand_gen(unsigned int seed = 
-                    static_cast<unsigned int>(std::time(0)));
-    
+    annotate_base()
+    {
+      label();
+      map_alloc();
+    }
+
+    static void
+    set_label(size_t l)
+    { label() = l; }
+
+    static size_t
+    get_label()
+    { return label(); }
+
     void
-    init(unsigned int);
-    
-    double
-    get_prob();
-    
-  private:
-    std::tr1::mt19937 _M_generator;
-  };
+    insert(void* p, size_t size)
+    {
+      if (!p)
+       {
+         std::string error("annotate_base::insert null insert!\n");
+         log_to_string(error, make_entry(p, size));
+         std::__throw_logic_error(error.c_str());
+       }
+
+      const_iterator found = map_alloc().find(p);
+      if (found != map_alloc().end())
+       {
+         std::string error("annotate_base::insert double insert!\n");
+         log_to_string(error, make_entry(p, size));
+         log_to_string(error, *found);
+         std::__throw_logic_error(error.c_str());
+       }
+
+      map_alloc().insert(make_entry(p, size));
+    }
 
+    void
+    erase(void* p, size_t size)
+    {
+      check_allocated(p, size);
+      map_alloc().erase(p);
+    }
 
-  struct forced_exception_error : public std::exception
-  { };
+#if __cplusplus >= 201103L
+    void
+    insert_construct(void* p)
+    {
+      if (!p)
+       {
+         std::string error("annotate_base::insert_construct null!\n");
+         std::__throw_logic_error(error.c_str());
+       }
+
+      auto found = map_construct().find(p);
+      if (found != map_construct().end())
+       {
+         std::string error("annotate_base::insert_construct double insert!\n");
+         log_to_string(error, std::make_pair(p, get_label()));
+         log_to_string(error, *found);
+         std::__throw_logic_error(error.c_str());
+       }
+
+      map_construct().insert(std::make_pair(p, get_label()));
+    }
 
-  class throw_allocator_base
-  {
-  public:
     void
-    init(unsigned long seed);
+    erase_construct(void* p)
+    {
+      check_constructed(p);
+      map_construct().erase(p);
+    }
+#endif
+
+    // See if a particular address and allocation size has been saved.
+    inline void
+    check_allocated(void* p, size_t size)
+    {
+      const_iterator found = map_alloc().find(p);
+      if (found == map_alloc().end())
+       {
+         std::string error("annotate_base::check_allocated by value "
+                           "null erase!\n");
+         log_to_string(error, make_entry(p, size));
+         std::__throw_logic_error(error.c_str());
+       }
+
+      if (found->second.second != size)
+       {
+         std::string error("annotate_base::check_allocated by value "
+                           "wrong-size erase!\n");
+         log_to_string(error, make_entry(p, size));
+         log_to_string(error, *found);
+         std::__throw_logic_error(error.c_str());
+       }
+    }
+
+    // See if a given label has been allocated.
+    inline void
+    check(size_t label)
+    {
+      std::string found;
+      {
+       const_iterator beg = map_alloc().begin();
+       const_iterator end = map_alloc().end();
+       while (beg != end)
+         {
+           if (beg->second.first == label)
+             log_to_string(found, *beg);
+           ++beg;
+         }
+      }
 
-    static void
-    set_throw_prob(double throw_prob);
+#if __cplusplus >= 201103L
+      {
+       auto beg = map_construct().begin();
+       auto end = map_construct().end();
+       while (beg != end)
+         {
+           if (beg->second == label)
+             log_to_string(found, *beg);
+           ++beg;
+         }
+      }
+#endif
+
+      if (!found.empty())
+       {
+         std::string error("annotate_base::check by label\n");
+         error += found;
+         std::__throw_logic_error(error.c_str());
+       }
+    }
+
+    // See if there is anything left allocated or constructed.
+    inline static void
+    check()
+    {
+      std::string found;
+      {
+       const_iterator beg = map_alloc().begin();
+       const_iterator end = map_alloc().end();
+       while (beg != end)
+         {
+           log_to_string(found, *beg);
+           ++beg;
+         }
+      }
 
-    static double
-    get_throw_prob();
+#if __cplusplus >= 201103L
+      {
+       auto beg = map_construct().begin();
+       auto end = map_construct().end();
+       while (beg != end)
+         {
+           log_to_string(found, *beg);
+           ++beg;
+         }
+      }
+#endif
+
+      if (!found.empty())
+       {
+         std::string error("annotate_base::check \n");
+         error += found;
+         std::__throw_logic_error(error.c_str());
+       }
+    }
+
+#if __cplusplus >= 201103L
+    inline void
+    check_constructed(void* p)
+    {
+      auto found = map_construct().find(p);
+      if (found == map_construct().end())
+       {
+         std::string error("annotate_base::check_constructed not "
+                           "constructed!\n");
+         log_to_string(error, std::make_pair(p, get_label()));
+         std::__throw_logic_error(error.c_str());
+       }
+    }
+
+    inline void
+    check_constructed(size_t label)
+    {
+      auto beg = map_construct().begin();
+      auto end = map_construct().end();
+      std::string found;
+      while (beg != end)
+       {
+         if (beg->second == label)
+           log_to_string(found, *beg);
+         ++beg;
+       }
+
+      if (!found.empty())
+       {
+         std::string error("annotate_base::check_constructed by label\n");
+         error += found;
+         std::__throw_logic_error(error.c_str());
+       }
+    }
+#endif
 
+  private:
+    typedef std::pair<size_t, size_t>          data_type;
+    typedef std::map<void*, data_type>                 map_alloc_type;
+    typedef map_alloc_type::value_type                 entry_type;
+    typedef map_alloc_type::const_iterator             const_iterator;
+    typedef map_alloc_type::const_reference            const_reference;
+#if __cplusplus >= 201103L
+    typedef std::map<void*, size_t>            map_construct_type;
+#endif
+
+    friend std::ostream&
+    operator<<(std::ostream&, const annotate_base&);
+
+    entry_type
+    make_entry(void* p, size_t size)
+    { return std::make_pair(p, data_type(get_label(), size)); }
+
+    static void
+    log_to_string(std::string& s, const_reference ref)
+    {
+      char buf[40];
+      const char tab('\t');
+      s += "label: ";
+      unsigned long l = static_cast<unsigned long>(ref.second.first);
+      __builtin_sprintf(buf, "%lu", l);
+      s += buf;
+      s += tab;
+      s += "size: ";
+      l = static_cast<unsigned long>(ref.second.second);
+      __builtin_sprintf(buf, "%lu", l);
+      s += buf;
+      s += tab;
+      s += "address: ";
+      __builtin_sprintf(buf, "%p", ref.first);
+      s += buf;
+      s += '\n';
+    }
+
+#if __cplusplus >= 201103L
     static void
-    set_label(size_t l);
+    log_to_string(std::string& s, const std::pair<const void*, size_t>& ref)
+    {
+      char buf[40];
+      const char tab('\t');
+      s += "label: ";
+      unsigned long l = static_cast<unsigned long>(ref.second);
+      __builtin_sprintf(buf, "%lu", l);
+      s += buf;
+      s += tab;
+      s += "address: ";
+      __builtin_sprintf(buf, "%p", ref.first);
+      s += buf;
+      s += '\n';
+    }
+#endif
+
+    static size_t&
+    label()
+    {
+      static size_t _S_label(std::numeric_limits<size_t>::max());
+      return _S_label;
+    }
 
-    static bool
-    empty();
+    static map_alloc_type&
+    map_alloc()
+    {
+      static map_alloc_type _S_map;
+      return _S_map;
+    }
 
-    struct group_throw_prob_adjustor
+#if __cplusplus >= 201103L
+    static map_construct_type&
+    map_construct()
     {
-      group_throw_prob_adjustor(size_t size) 
-      : _M_throw_prob_orig(_S_throw_prob)
-      {
-       _S_throw_prob =
-         1 - ::pow(double(1 - _S_throw_prob), double(0.5 / (size + 1)));
-      }
+      static map_construct_type _S_map;
+      return _S_map;
+    }
+#endif
+  };
+
+  inline std::ostream&
+  operator<<(std::ostream& os, const annotate_base& __b)
+  {
+    std::string error;
+    typedef annotate_base base_type;
+    {
+      base_type::const_iterator beg = __b.map_alloc().begin();
+      base_type::const_iterator end = __b.map_alloc().end();
+      for (; beg != end; ++beg)
+       __b.log_to_string(error, *beg);
+    }
+#if __cplusplus >= 201103L
+    {
+      auto beg = __b.map_construct().begin();
+      auto end = __b.map_construct().end();
+      for (; beg != end; ++beg)
+       __b.log_to_string(error, *beg);      
+    }
+#endif
+    return os << error;
+  }
+
+
+  /**
+   *  @brief Base struct for condition policy.
+   *
+   * Requires a public member function with the signature
+   * void throw_conditionally()
+   */
+  struct condition_base
+  {
+    virtual ~condition_base() { };
+  };
 
-      ~group_throw_prob_adjustor()
-      { _S_throw_prob = _M_throw_prob_orig; }
 
+  /**
+   *  @brief Base class for incremental control and throw.
+   */
+  struct limit_condition : public condition_base
+  {
+    // Scope-level adjustor objects: set limit for throw at the
+    // beginning of a scope block, and restores to previous limit when
+    // object is destroyed on exiting the block.
+    struct adjustor_base
+    {
     private:
-      const double _M_throw_prob_orig;
+      const size_t _M_orig;
+
+    public:
+      adjustor_base() : _M_orig(limit()) { }
+
+      virtual
+      ~adjustor_base() { set_limit(_M_orig); }
     };
 
-    struct zero_throw_prob_adjustor
+    /// Never enter the condition.
+    struct never_adjustor : public adjustor_base
     {
-      zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob)
-      { _S_throw_prob = 0; }
+      never_adjustor() { set_limit(std::numeric_limits<size_t>::max()); }
+    };
 
-      ~zero_throw_prob_adjustor()
-      { _S_throw_prob = _M_throw_prob_orig; }
+    /// Always enter the condition.
+    struct always_adjustor : public adjustor_base
+    {
+      always_adjustor() { set_limit(count()); }
+    };
 
-    private:
-      const double _M_throw_prob_orig;
+    /// Enter the nth condition.
+    struct limit_adjustor : public adjustor_base
+    {
+      limit_adjustor(const size_t __l) { set_limit(__l); }
     };
 
-  protected:
+    // Increment _S_count every time called.
+    // If _S_count matches the limit count, throw.
     static void
-    insert(void*, size_t);
+    throw_conditionally()
+    {
+      if (count() == limit())
+       __throw_forced_error();
+      ++count();
+    }
 
-    static void
-    erase(void*, size_t);
+    static size_t&
+    count()
+    {
+      static size_t _S_count(0);
+      return _S_count;
+    }
 
-    static void
-    throw_conditionally();
+    static size_t&
+    limit()
+    {
+      static size_t _S_limit(std::numeric_limits<size_t>::max());
+      return _S_limit;
+    }
 
+    // Zero the throw counter, set limit to argument.
     static void
-    assert_allocatod(const void*, size_t);
+    set_limit(const size_t __l)
+    {
+      limit() = __l;
+      count() = 0;
+    }
+  };
 
-    static void
-    check_allocated(void*, size_t);
 
-  private:
-    typedef std::pair<size_t, size_t>          alloc_data_type;
-    typedef std::map<void*, alloc_data_type>   map_type;
-    typedef map_type::value_type               entry_type;
-    typedef map_type::const_iterator           const_iterator;
-    typedef map_type::const_reference          const_reference;
+  /**
+   *  @brief Base class for random probability control and throw.
+   */
+  struct random_condition : public condition_base
+  {
+    // Scope-level adjustor objects: set probability for throw at the
+    // beginning of a scope block, and restores to previous
+    // probability when object is destroyed on exiting the block.
+    struct adjustor_base
+    {
+    private:
+      const double _M_orig;
+
+    public:
+      adjustor_base() : _M_orig(probability()) { }
+
+      virtual ~adjustor_base()
+      { set_probability(_M_orig); }
+    };
+
+    /// Group condition.
+    struct group_adjustor : public adjustor_base
+    {
+      group_adjustor(size_t size)
+      { set_probability(1 - std::pow(double(1 - probability()),
+                                    double(0.5 / (size + 1))));
+      }
+    };
+
+    /// Never enter the condition.
+    struct never_adjustor : public adjustor_base
+    {
+      never_adjustor() { set_probability(0); }
+    };
 
-    friend std::ostream& 
-    operator<<(std::ostream&, const throw_allocator_base&);
+    /// Always enter the condition.
+    struct always_adjustor : public adjustor_base
+    {
+      always_adjustor() { set_probability(1); }
+    };
 
-    static entry_type
-    make_entry(void*, size_t);
+    random_condition()
+    {
+      probability();
+      engine();
+    }
 
     static void
-    print_to_string(std::string&);
+    set_probability(double __p)
+    { probability() = __p; }
 
     static void
-    print_to_string(std::string&, const_reference);
+    throw_conditionally()
+    {
+      if (generate() < probability())
+       __throw_forced_error();
+    }
 
-    static twister_rand_gen    _S_g;
-    static map_type            _S_map;
-    static double              _S_throw_prob;
-    static size_t              _S_label;
+    void
+    seed(unsigned long __s)
+    { engine().seed(__s); }
+
+  private:
+#if __cplusplus >= 201103L
+    typedef std::uniform_real_distribution<double>     distribution_type;
+    typedef std::mt19937                               engine_type;
+#else
+    typedef std::tr1::uniform_real<double>             distribution_type;
+    typedef std::tr1::mt19937                          engine_type;
+#endif
+
+    static double
+    generate()
+    {
+#if __cplusplus >= 201103L
+      const distribution_type distribution(0, 1);
+      static auto generator = std::bind(distribution, engine());
+#else
+      // Use variate_generator to get normalized results.
+      typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t;
+      distribution_type distribution(0, 1);
+      static gen_t generator(engine(), distribution);
+#endif
+
+      double random = generator();
+      if (random < distribution.min() || random > distribution.max())
+       {
+         std::string __s("random_condition::generate");
+         __s += "\n";
+         __s += "random number generated is: ";
+         char buf[40];
+         __builtin_sprintf(buf, "%f", random);
+         __s += buf;
+         std::__throw_out_of_range(__s.c_str());
+       }
+
+      return random;
+    }
+
+    static double&
+    probability()
+    {
+      static double _S_p;
+      return _S_p;
+    }
+
+    static engine_type&
+    engine()
+    {
+      static engine_type _S_e;
+      return _S_e;
+    }
   };
 
 
-  template<typename T>
-    class throw_allocator : public throw_allocator_base
+  /**
+   *  @brief Class with exception generation control. Intended to be
+   *  used as a value_type in templatized code.
+   *
+   *  Note: Destructor not allowed to throw.
+   */
+  template<typename _Cond>
+    struct throw_value_base : public _Cond
     {
-    public:
-      typedef size_t           size_type;
-      typedef ptrdiff_t        difference_type;
-      typedef T*               pointer;
-      typedef const T*                 const_pointer;
-      typedef T&               reference;
-      typedef const T&                 const_reference;
-      typedef T                value_type;
-
-      template<typename U>
-      struct rebind
-      {
-        typedef throw_allocator<U> other;
-      };
+      typedef _Cond                            condition_type;
 
-      throw_allocator() throw() { }
+      using condition_type::throw_conditionally;
 
-      throw_allocator(const throw_allocator<T>&) throw() { }
+      std::size_t                              _M_i;
 
-      template <class U>
-      throw_allocator(const throw_allocator<U>&) throw() { }
+#ifndef _GLIBCXX_IS_AGGREGATE
+      throw_value_base() : _M_i(0)
+      { throw_conditionally(); }
 
-      ~throw_allocator() throw() { }
+      throw_value_base(const throw_value_base& __v) : _M_i(__v._M_i)
+      { throw_conditionally(); }
 
-      size_type
-      max_size() const throw()
-      { return std::allocator<T>().max_size(); }
+#if __cplusplus >= 201103L
+      // Shall not throw.
+      throw_value_base(throw_value_base&&) = default;
+#endif
 
-      pointer
-      allocate(size_type num, std::allocator<void>::const_pointer hint = 0)
+      explicit throw_value_base(const std::size_t __i) : _M_i(__i)
+      { throw_conditionally(); }
+#endif
+
+      throw_value_base&
+      operator=(const throw_value_base& __v)
       {
        throw_conditionally();
-       T* const a = std::allocator<T>().allocate(num, hint);
-       insert(a, sizeof(T) * num);
-       return a;
+       _M_i = __v._M_i;
+       return *this;
       }
 
-      void
-      construct(pointer p, const T& val)
-      { return std::allocator<T>().construct(p, val); }
-
-      void
-      destroy(pointer p)
-      {        std::allocator<T>().destroy(p); }
+#if __cplusplus >= 201103L
+      // Shall not throw.
+      throw_value_base&
+      operator=(throw_value_base&&) = default;
+#endif
 
-      void
-      deallocate(pointer p, size_type num)
+      throw_value_base&
+      operator++()
       {
-       erase(p, sizeof(T) * num);
-       std::allocator<T>().deallocate(p, num);
+       throw_conditionally();
+       ++_M_i;
+       return *this;
       }
-
-      void
-      check_allocated(pointer p, size_type num)
-      { throw_allocator_base::check_allocated(p, sizeof(T) * num); }
     };
 
-  template<typename T>
+  template<typename _Cond>
+    inline void
+    swap(throw_value_base<_Cond>& __a, throw_value_base<_Cond>& __b)
+    {
+      typedef throw_value_base<_Cond> throw_value;
+      throw_value::throw_conditionally();
+      throw_value orig(__a);
+      __a = __b;
+      __b = orig;
+    }
+
+  // General instantiable types requirements.
+  template<typename _Cond>
     inline bool
-    operator==(const throw_allocator<T>&, const throw_allocator<T>&)
-    { return true; }
+    operator==(const throw_value_base<_Cond>& __a,
+              const throw_value_base<_Cond>& __b)
+    {
+      typedef throw_value_base<_Cond> throw_value;
+      throw_value::throw_conditionally();
+      bool __ret = __a._M_i == __b._M_i;
+      return __ret;
+    }
 
-  template<typename T>
+  template<typename _Cond>
     inline bool
-    operator!=(const throw_allocator<T>&, const throw_allocator<T>&)
-    { return false; }
+    operator<(const throw_value_base<_Cond>& __a,
+             const throw_value_base<_Cond>& __b)
+    {
+      typedef throw_value_base<_Cond> throw_value;
+      throw_value::throw_conditionally();
+      bool __ret = __a._M_i < __b._M_i;
+      return __ret;
+    }
+
+  // Numeric algorithms instantiable types requirements.
+  template<typename _Cond>
+    inline throw_value_base<_Cond>
+    operator+(const throw_value_base<_Cond>& __a,
+             const throw_value_base<_Cond>& __b)
+    {
+      typedef throw_value_base<_Cond> throw_value;
+      throw_value::throw_conditionally();
+      throw_value __ret(__a._M_i + __b._M_i);
+      return __ret;
+    }
+
+  template<typename _Cond>
+    inline throw_value_base<_Cond>
+    operator-(const throw_value_base<_Cond>& __a,
+             const throw_value_base<_Cond>& __b)
+    {
+      typedef throw_value_base<_Cond> throw_value;
+      throw_value::throw_conditionally();
+      throw_value __ret(__a._M_i - __b._M_i);
+      return __ret;
+    }
+
+  template<typename _Cond>
+    inline throw_value_base<_Cond>
+    operator*(const throw_value_base<_Cond>& __a,
+             const throw_value_base<_Cond>& __b)
+    {
+      typedef throw_value_base<_Cond> throw_value;
+      throw_value::throw_conditionally();
+      throw_value __ret(__a._M_i * __b._M_i);
+      return __ret;
+    }
 
-  std::ostream& 
-  operator<<(std::ostream& os, const throw_allocator_base& alloc)
+
+  /// Type throwing via limit condition.
+  struct throw_value_limit : public throw_value_base<limit_condition>
   {
-    std::string error;
-    throw_allocator_base::print_to_string(error);
-    os << error;
-    return os;
-  }
+    typedef throw_value_base<limit_condition> base_type;
+
+#ifndef _GLIBCXX_IS_AGGREGATE
+    throw_value_limit() { }
+
+    throw_value_limit(const throw_value_limit& __other)
+    : base_type(__other._M_i) { }
+
+#if __cplusplus >= 201103L
+    throw_value_limit(throw_value_limit&&) = default;
+#endif
 
-  // XXX Should be in .cc.
-  twister_rand_gen::
-  twister_rand_gen(unsigned int seed) : _M_generator(seed)  { }
+    explicit throw_value_limit(const std::size_t __i) : base_type(__i) { }
+#endif
 
-  void
-  twister_rand_gen::
-  init(unsigned int seed)
-  { _M_generator.seed(seed); }
+    throw_value_limit&
+    operator=(const throw_value_limit& __other)
+    {
+      base_type::operator=(__other);
+      return *this;
+    }
+
+#if __cplusplus >= 201103L
+    throw_value_limit&
+    operator=(throw_value_limit&&) = default;
+#endif
+  };
 
-  double
-  twister_rand_gen::
-  get_prob()
+  /// Type throwing via random condition.
+  struct throw_value_random : public throw_value_base<random_condition>
   {
-    const double eng_min = _M_generator.min();
-    const double eng_range =
-      static_cast<const double>(_M_generator.max() - eng_min);
+    typedef throw_value_base<random_condition> base_type;
 
-    const double eng_res =
-      static_cast<const double>(_M_generator() - eng_min);
+#ifndef _GLIBCXX_IS_AGGREGATE
+    throw_value_random() { }
 
-    const double ret = eng_res / eng_range;
-    _GLIBCXX_DEBUG_ASSERT(ret >= 0 && ret <= 1);
-    return ret;
-  }
+    throw_value_random(const throw_value_random& __other)
+    : base_type(__other._M_i) { }
 
-  twister_rand_gen throw_allocator_base::_S_g;
+#if __cplusplus >= 201103L
+    throw_value_random(throw_value_random&&) = default;
+#endif
+
+    explicit throw_value_random(const std::size_t __i) : base_type(__i) { }
+#endif
+
+    throw_value_random&
+    operator=(const throw_value_random& __other)
+    {
+      base_type::operator=(__other);
+      return *this;
+    }
+
+#if __cplusplus >= 201103L
+    throw_value_random&
+    operator=(throw_value_random&&) = default;
+#endif
+  };
 
-  throw_allocator_base::map_type
-  throw_allocator_base::_S_map;
 
-  double throw_allocator_base::_S_throw_prob;
+  /**
+   *  @brief Allocator class with logging and exception generation control.
+   * Intended to be used as an allocator_type in templatized code.
+   *  @ingroup allocators
+   *
+   *  Note: Deallocate not allowed to throw.
+   */
+  template<typename _Tp, typename _Cond>
+    class throw_allocator_base
+    : public annotate_base, public _Cond
+    {
+    public:
+      typedef size_t                           size_type;
+      typedef ptrdiff_t                        difference_type;
+      typedef _Tp                              value_type;
+      typedef value_type*                      pointer;
+      typedef const value_type*                const_pointer;
+      typedef value_type&                      reference;
+      typedef const value_type&                const_reference;
+
+#if __cplusplus >= 201103L
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 2103. std::allocator propagate_on_container_move_assignment
+      typedef std::true_type propagate_on_container_move_assignment;
+#endif
 
-  size_t throw_allocator_base::_S_label = 0;
+    private:
+      typedef _Cond                            condition_type;
 
-  throw_allocator_base::entry_type
-  throw_allocator_base::make_entry(void* p, size_t size)
-  { return std::make_pair(p, alloc_data_type(_S_label, size)); }
+      std::allocator<value_type>               _M_allocator;
 
-  void
-  throw_allocator_base::init(unsigned long seed)
-  { _S_g.init(seed); }
+      using condition_type::throw_conditionally;
 
-  void
-  throw_allocator_base::set_throw_prob(double throw_prob)
-  { _S_throw_prob = throw_prob; }
+    public:
+      size_type
+      max_size() const _GLIBCXX_USE_NOEXCEPT
+      { return _M_allocator.max_size(); }
 
-  double
-  throw_allocator_base::get_throw_prob()
-  { return _S_throw_prob; }
+      pointer
+      address(reference __x) const _GLIBCXX_NOEXCEPT
+      { return std::__addressof(__x); }
 
-  void
-  throw_allocator_base::set_label(size_t l)
-  { _S_label = l; }
+      const_pointer
+      address(const_reference __x) const _GLIBCXX_NOEXCEPT
+      { return std::__addressof(__x); }
 
-  void
-  throw_allocator_base::insert(void* p, size_t size)
-  {
-    const_iterator found_it = _S_map.find(p);
-    if (found_it != _S_map.end())
+      pointer
+      allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
       {
-       std::string error("throw_allocator_base::insert");
-       error += "double insert!";
-       error += '\n';
-       print_to_string(error, make_entry(p, size));
-       print_to_string(error, *found_it);
-       throw std::logic_error(error);
+       if (__n > this->max_size())
+         std::__throw_bad_alloc();
+
+       throw_conditionally();
+       pointer const a = _M_allocator.allocate(__n, hint);
+       insert(a, sizeof(value_type) * __n);
+       return a;
       }
-    _S_map.insert(make_entry(p, size));
-  }
 
-  bool
-  throw_allocator_base::empty()
-  { return _S_map.empty(); }
+#if __cplusplus >= 201103L
+      template<typename _Up, typename... _Args>
+        void
+        construct(_Up* __p, _Args&&... __args)
+       {
+         _M_allocator.construct(__p, std::forward<_Args>(__args)...);
+         insert_construct(__p);
+       }
+
+      template<typename _Up>
+        void 
+        destroy(_Up* __p)
+        {
+         erase_construct(__p);
+         _M_allocator.destroy(__p);
+       }
+#else
+      void
+      construct(pointer __p, const value_type& val)
+      { return _M_allocator.construct(__p, val); }
 
-  void
-  throw_allocator_base::erase(void* p, size_t size)
-  {
-    check_allocated(p, size);
-    _S_map.erase(p);
-  }
+      void
+      destroy(pointer __p)
+      { _M_allocator.destroy(__p); }
+#endif
 
-  void
-  throw_allocator_base::check_allocated(void* p, size_t size)
-  {
-    const_iterator found_it = _S_map.find(p);
-    if (found_it == _S_map.end())
+      void
+      deallocate(pointer __p, size_type __n)
       {
-       std::string error("throw_allocator_base::check_allocated");
-       error += "null erase!";
-       error += '\n';
-       print_to_string(error, make_entry(p, size));
-       throw std::logic_error(error);
+       erase(__p, sizeof(value_type) * __n);
+       _M_allocator.deallocate(__p, __n);
       }
 
-    if (found_it->second.second != size)
+      void
+      check_allocated(pointer __p, size_type __n)
       {
-       std::string error("throw_allocator_base::check_allocated");
-       error += "wrong-size erase!";
-       error += '\n';
-       print_to_string(error, make_entry(p, size));
-       print_to_string(error, *found_it);
-       throw std::logic_error(error);
+       size_type __t = sizeof(value_type) * __n;
+       annotate_base::check_allocated(__p, __t);
       }
-  }
 
-  void
-  throw_allocator_base::throw_conditionally()
-  {
-    if (_S_g.get_prob() < _S_throw_prob)
-      throw forced_exception_error();
-  }
+      void
+      check(size_type __n)
+      { annotate_base::check(__n); }
+  };
 
-  void
-  throw_allocator_base::print_to_string(std::string& s)
-  {
-    const_iterator it = throw_allocator_base::_S_map.begin();
-    const_iterator end_it = throw_allocator_base::_S_map.end();
-    for (; it != end_it; ++it)
-      print_to_string(s, *it);
-    s += '\n';
-  }
+  template<typename _Tp, typename _Cond>
+    inline bool
+    operator==(const throw_allocator_base<_Tp, _Cond>&,
+              const throw_allocator_base<_Tp, _Cond>&)
+    { return true; }
 
-  void
-  throw_allocator_base::print_to_string(std::string& s, const_reference ref)
-  {
-    s += reinterpret_cast<const unsigned long>(ref.first);
-    s += ": ";
-    s += ref.second.first ;
-    s += ", ";
-    s += ref.second.second;
-    s += '\n';
-  }
+  template<typename _Tp, typename _Cond>
+    inline bool
+    operator!=(const throw_allocator_base<_Tp, _Cond>&,
+              const throw_allocator_base<_Tp, _Cond>&)
+    { return false; }
+
+  /// Allocator throwing via limit condition.
+  template<typename _Tp>
+    struct throw_allocator_limit
+    : public throw_allocator_base<_Tp, limit_condition>
+    {
+      template<typename _Tp1>
+       struct rebind
+       { typedef throw_allocator_limit<_Tp1> other; };
+
+      throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
 
-_GLIBCXX_END_NAMESPACE
+      throw_allocator_limit(const throw_allocator_limit&)
+      _GLIBCXX_USE_NOEXCEPT { }
+
+      template<typename _Tp1>
+       throw_allocator_limit(const throw_allocator_limit<_Tp1>&)
+       _GLIBCXX_USE_NOEXCEPT { }
+
+      ~throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
+    };
+
+  /// Allocator throwing via random condition.
+  template<typename _Tp>
+    struct throw_allocator_random
+    : public throw_allocator_base<_Tp, random_condition>
+    {
+      template<typename _Tp1>
+       struct rebind
+       { typedef throw_allocator_random<_Tp1> other; };
+
+      throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
+
+      throw_allocator_random(const throw_allocator_random&)
+      _GLIBCXX_USE_NOEXCEPT { }
+
+      template<typename _Tp1>
+       throw_allocator_random(const throw_allocator_random<_Tp1>&)
+       _GLIBCXX_USE_NOEXCEPT { }
+
+      ~throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
+    };
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+
+#if __cplusplus >= 201103L
+
+# include <bits/functional_hash.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+  /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
+  template<>
+    struct hash<__gnu_cxx::throw_value_limit>
+    : public std::unary_function<__gnu_cxx::throw_value_limit, size_t>
+    {
+      size_t
+      operator()(const __gnu_cxx::throw_value_limit& __val) const
+      {
+       __gnu_cxx::throw_value_limit::throw_conditionally();
+       std::hash<std::size_t> __h;
+       size_t __result = __h(__val._M_i);
+       return __result;
+      }
+    };
+
+  /// Explicit specialization of std::hash for __gnu_cxx::throw_value_random.
+  template<>
+    struct hash<__gnu_cxx::throw_value_random>
+    : public std::unary_function<__gnu_cxx::throw_value_random, size_t>
+    {
+      size_t
+      operator()(const __gnu_cxx::throw_value_random& __val) const
+      {
+       __gnu_cxx::throw_value_random::throw_conditionally();
+       std::hash<std::size_t> __h;
+       size_t __result = __h(__val._M_i);
+       return __result;
+      }
+    };
+} // end namespace std
+#endif
 
-#endif 
+#endif