Home | History | Annotate | Download | only in ext
      1 // -*- C++ -*-
      2 
      3 // Copyright (C) 2005-2013 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the terms
      7 // of the GNU General Public License as published by the Free Software
      8 // Foundation; either version 3, or (at your option) any later
      9 // version.
     10 
     11 // This library is distributed in the hope that it will be useful, but
     12 // WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 // General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
     26 
     27 // Permission to use, copy, modify, sell, and distribute this software
     28 // is hereby granted without fee, provided that the above copyright
     29 // notice appears in all copies, and that both that copyright notice
     30 // and this permission notice appear in supporting documentation. None
     31 // of the above authors, nor IBM Haifa Research Laboratories, make any
     32 // representation about the suitability of this software for any
     33 // purpose. It is provided "as is" without express or implied
     34 // warranty.
     35 
     36 /** @file ext/throw_allocator.h
     37  *  This file is a GNU extension to the Standard C++ Library.
     38  *
     39  *  Contains two exception-generating types (throw_value, throw_allocator)
     40  *  intended to be used as value and allocator types while testing
     41  *  exception safety in templatized containers and algorithms. The
     42  *  allocator has additional log and debug features. The exception
     43  *  generated is of type forced_exception_error.
     44  */
     45 
     46 #ifndef _THROW_ALLOCATOR_H
     47 #define _THROW_ALLOCATOR_H 1
     48 
     49 #include <cmath>
     50 #include <ctime>
     51 #include <map>
     52 #include <string>
     53 #include <ostream>
     54 #include <stdexcept>
     55 #include <utility>
     56 #include <bits/functexcept.h>
     57 #include <bits/move.h>
     58 #if __cplusplus >= 201103L
     59 # include <functional>
     60 # include <random>
     61 #else
     62 # include <tr1/functional>
     63 # include <tr1/random>
     64 #endif
     65 
     66 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
     67 {
     68 _GLIBCXX_BEGIN_NAMESPACE_VERSION
     69 
     70   /**
     71    *  @brief Thown by exception safety machinery.
     72    *  @ingroup exceptions
     73    */
     74   struct forced_error : public std::exception
     75   { };
     76 
     77   // Substitute for forced_error object when -fno-exceptions.
     78   inline void
     79   __throw_forced_error()
     80   { _GLIBCXX_THROW_OR_ABORT(forced_error()); }
     81 
     82   /**
     83    *  @brief Base class for checking address and label information
     84    *  about allocations. Create a std::map between the allocated
     85    *  address (void*) and a datum for annotations, which are a pair of
     86    *  numbers corresponding to label and allocated size.
     87    */
     88   struct annotate_base
     89   {
     90     annotate_base()
     91     {
     92       label();
     93       map();
     94     }
     95 
     96     static void
     97     set_label(size_t l)
     98     { label() = l; }
     99 
    100     static size_t
    101     get_label()
    102     { return label(); }
    103 
    104     void
    105     insert(void* p, size_t size)
    106     {
    107       if (!p)
    108 	{
    109 	  std::string error("annotate_base::insert null insert!\n");
    110 	  log_to_string(error, make_entry(p, size));
    111 	  std::__throw_logic_error(error.c_str());
    112 	}
    113 
    114       const_iterator found = map().find(p);
    115       if (found != map().end())
    116 	{
    117 	  std::string error("annotate_base::insert double insert!\n");
    118 	  log_to_string(error, make_entry(p, size));
    119 	  log_to_string(error, *found);
    120 	  std::__throw_logic_error(error.c_str());
    121 	}
    122 
    123       map().insert(make_entry(p, size));
    124     }
    125 
    126     void
    127     erase(void* p, size_t size)
    128     {
    129       check_allocated(p, size);
    130       map().erase(p);
    131     }
    132 
    133     // See if a particular address and allocation size has been saved.
    134     inline void
    135     check_allocated(void* p, size_t size)
    136     {
    137       const_iterator found = map().find(p);
    138       if (found == map().end())
    139 	{
    140 	  std::string error("annotate_base::check_allocated by value "
    141 			    "null erase!\n");
    142 	  log_to_string(error, make_entry(p, size));
    143 	  std::__throw_logic_error(error.c_str());
    144 	}
    145 
    146       if (found->second.second != size)
    147 	{
    148 	  std::string error("annotate_base::check_allocated by value "
    149 			    "wrong-size erase!\n");
    150 	  log_to_string(error, make_entry(p, size));
    151 	  log_to_string(error, *found);
    152 	  std::__throw_logic_error(error.c_str());
    153 	}
    154     }
    155 
    156     // See if a given label has been allocated.
    157     inline void
    158     check_allocated(size_t label)
    159     {
    160       const_iterator beg = map().begin();
    161       const_iterator end = map().end();
    162       std::string found;
    163       while (beg != end)
    164 	{
    165 	  if (beg->second.first == label)
    166 	    log_to_string(found, *beg);
    167 	  ++beg;
    168 	}
    169 
    170       if (!found.empty())
    171 	{
    172 	  std::string error("annotate_base::check_allocated by label\n");
    173 	  error += found;
    174 	  std::__throw_logic_error(error.c_str());
    175 	}
    176     }
    177 
    178   private:
    179     typedef std::pair<size_t, size_t> 		data_type;
    180     typedef std::map<void*, data_type> 		map_type;
    181     typedef map_type::value_type 		entry_type;
    182     typedef map_type::const_iterator 		const_iterator;
    183     typedef map_type::const_reference 		const_reference;
    184 
    185     friend std::ostream&
    186     operator<<(std::ostream&, const annotate_base&);
    187 
    188     entry_type
    189     make_entry(void* p, size_t size)
    190     { return std::make_pair(p, data_type(get_label(), size)); }
    191 
    192     void
    193     log_to_string(std::string& s, const_reference ref) const
    194     {
    195       char buf[40];
    196       const char tab('\t');
    197       s += "label: ";
    198       unsigned long l = static_cast<unsigned long>(ref.second.first);
    199       __builtin_sprintf(buf, "%lu", l);
    200       s += buf;
    201       s += tab;
    202       s += "size: ";
    203       l = static_cast<unsigned long>(ref.second.second);
    204       __builtin_sprintf(buf, "%lu", l);
    205       s += buf;
    206       s += tab;
    207       s += "address: ";
    208       __builtin_sprintf(buf, "%p", ref.first);
    209       s += buf;
    210       s += '\n';
    211     }
    212 
    213     static size_t&
    214     label()
    215     {
    216       static size_t _S_label(std::numeric_limits<size_t>::max());
    217       return _S_label;
    218     }
    219 
    220     static map_type&
    221     map()
    222     {
    223       static map_type _S_map;
    224       return _S_map;
    225     }
    226   };
    227 
    228   inline std::ostream&
    229   operator<<(std::ostream& os, const annotate_base& __b)
    230   {
    231     std::string error;
    232     typedef annotate_base base_type;
    233     base_type::const_iterator beg = __b.map().begin();
    234     base_type::const_iterator end = __b.map().end();
    235     for (; beg != end; ++beg)
    236       __b.log_to_string(error, *beg);
    237     return os << error;
    238   }
    239 
    240 
    241   /**
    242    *  @brief Base struct for condition policy.
    243    *
    244    * Requires a public member function with the signature
    245    * void throw_conditionally()
    246    */
    247   struct condition_base
    248   {
    249     virtual ~condition_base() { };
    250   };
    251 
    252 
    253   /**
    254    *  @brief Base class for incremental control and throw.
    255    */
    256   struct limit_condition : public condition_base
    257   {
    258     // Scope-level adjustor objects: set limit for throw at the
    259     // beginning of a scope block, and restores to previous limit when
    260     // object is destroyed on exiting the block.
    261     struct adjustor_base
    262     {
    263     private:
    264       const size_t _M_orig;
    265 
    266     public:
    267       adjustor_base() : _M_orig(limit()) { }
    268 
    269       virtual
    270       ~adjustor_base() { set_limit(_M_orig); }
    271     };
    272 
    273     /// Never enter the condition.
    274     struct never_adjustor : public adjustor_base
    275     {
    276       never_adjustor() { set_limit(std::numeric_limits<size_t>::max()); }
    277     };
    278 
    279     /// Always enter the condition.
    280     struct always_adjustor : public adjustor_base
    281     {
    282       always_adjustor() { set_limit(count()); }
    283     };
    284 
    285     /// Enter the nth condition.
    286     struct limit_adjustor : public adjustor_base
    287     {
    288       limit_adjustor(const size_t __l) { set_limit(__l); }
    289     };
    290 
    291     // Increment _S_count every time called.
    292     // If _S_count matches the limit count, throw.
    293     static void
    294     throw_conditionally()
    295     {
    296       if (count() == limit())
    297 	__throw_forced_error();
    298       ++count();
    299     }
    300 
    301     static size_t&
    302     count()
    303     {
    304       static size_t _S_count(0);
    305       return _S_count;
    306     }
    307 
    308     static size_t&
    309     limit()
    310     {
    311       static size_t _S_limit(std::numeric_limits<size_t>::max());
    312       return _S_limit;
    313     }
    314 
    315     // Zero the throw counter, set limit to argument.
    316     static void
    317     set_limit(const size_t __l)
    318     {
    319       limit() = __l;
    320       count() = 0;
    321     }
    322   };
    323 
    324 
    325   /**
    326    *  @brief Base class for random probability control and throw.
    327    */
    328   struct random_condition : public condition_base
    329   {
    330     // Scope-level adjustor objects: set probability for throw at the
    331     // beginning of a scope block, and restores to previous
    332     // probability when object is destroyed on exiting the block.
    333     struct adjustor_base
    334     {
    335     private:
    336       const double _M_orig;
    337 
    338     public:
    339       adjustor_base() : _M_orig(probability()) { }
    340 
    341       virtual ~adjustor_base()
    342       { set_probability(_M_orig); }
    343     };
    344 
    345     /// Group condition.
    346     struct group_adjustor : public adjustor_base
    347     {
    348       group_adjustor(size_t size)
    349       { set_probability(1 - std::pow(double(1 - probability()),
    350 				     double(0.5 / (size + 1))));
    351       }
    352     };
    353 
    354     /// Never enter the condition.
    355     struct never_adjustor : public adjustor_base
    356     {
    357       never_adjustor() { set_probability(0); }
    358     };
    359 
    360     /// Always enter the condition.
    361     struct always_adjustor : public adjustor_base
    362     {
    363       always_adjustor() { set_probability(1); }
    364     };
    365 
    366     random_condition()
    367     {
    368       probability();
    369       engine();
    370     }
    371 
    372     static void
    373     set_probability(double __p)
    374     { probability() = __p; }
    375 
    376     static void
    377     throw_conditionally()
    378     {
    379       if (generate() < probability())
    380 	__throw_forced_error();
    381     }
    382 
    383     void
    384     seed(unsigned long __s)
    385     { engine().seed(__s); }
    386 
    387   private:
    388 #if __cplusplus >= 201103L
    389     typedef std::uniform_real_distribution<double> 	distribution_type;
    390     typedef std::mt19937 				engine_type;
    391 #else
    392     typedef std::tr1::uniform_real<double> 		distribution_type;
    393     typedef std::tr1::mt19937 				engine_type;
    394 #endif
    395 
    396     static double
    397     generate()
    398     {
    399 #if __cplusplus >= 201103L
    400       const distribution_type distribution(0, 1);
    401       static auto generator = std::bind(distribution, engine());
    402 #else
    403       // Use variate_generator to get normalized results.
    404       typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t;
    405       distribution_type distribution(0, 1);
    406       static gen_t generator(engine(), distribution);
    407 #endif
    408 
    409       double random = generator();
    410       if (random < distribution.min() || random > distribution.max())
    411 	{
    412 	  std::string __s("random_condition::generate");
    413 	  __s += "\n";
    414 	  __s += "random number generated is: ";
    415 	  char buf[40];
    416 	  __builtin_sprintf(buf, "%f", random);
    417 	  __s += buf;
    418 	  std::__throw_out_of_range(__s.c_str());
    419 	}
    420 
    421       return random;
    422     }
    423 
    424     static double&
    425     probability()
    426     {
    427       static double _S_p;
    428       return _S_p;
    429     }
    430 
    431     static engine_type&
    432     engine()
    433     {
    434       static engine_type _S_e;
    435       return _S_e;
    436     }
    437   };
    438 
    439 
    440   /**
    441    *  @brief Class with exception generation control. Intended to be
    442    *  used as a value_type in templatized code.
    443    *
    444    *  Note: Destructor not allowed to throw.
    445    */
    446   template<typename _Cond>
    447     struct throw_value_base : public _Cond
    448     {
    449       typedef _Cond  				condition_type;
    450 
    451       using condition_type::throw_conditionally;
    452 
    453       std::size_t			       	_M_i;
    454 
    455 #ifndef _GLIBCXX_IS_AGGREGATE
    456       throw_value_base() : _M_i(0)
    457       { throw_conditionally(); }
    458 
    459       throw_value_base(const throw_value_base& __v) : _M_i(__v._M_i)
    460       { throw_conditionally(); }
    461 
    462 #if __cplusplus >= 201103L
    463       // Shall not throw.
    464       throw_value_base(throw_value_base&&) = default;
    465 #endif
    466 
    467       explicit throw_value_base(const std::size_t __i) : _M_i(__i)
    468       { throw_conditionally(); }
    469 #endif
    470 
    471       throw_value_base&
    472       operator=(const throw_value_base& __v)
    473       {
    474 	throw_conditionally();
    475 	_M_i = __v._M_i;
    476 	return *this;
    477       }
    478 
    479 #if __cplusplus >= 201103L
    480       // Shall not throw.
    481       throw_value_base&
    482       operator=(throw_value_base&&) = default;
    483 #endif
    484 
    485       throw_value_base&
    486       operator++()
    487       {
    488 	throw_conditionally();
    489 	++_M_i;
    490 	return *this;
    491       }
    492     };
    493 
    494   template<typename _Cond>
    495     inline void
    496     swap(throw_value_base<_Cond>& __a, throw_value_base<_Cond>& __b)
    497     {
    498       typedef throw_value_base<_Cond> throw_value;
    499       throw_value::throw_conditionally();
    500       throw_value orig(__a);
    501       __a = __b;
    502       __b = orig;
    503     }
    504 
    505   // General instantiable types requirements.
    506   template<typename _Cond>
    507     inline bool
    508     operator==(const throw_value_base<_Cond>& __a,
    509 	       const throw_value_base<_Cond>& __b)
    510     {
    511       typedef throw_value_base<_Cond> throw_value;
    512       throw_value::throw_conditionally();
    513       bool __ret = __a._M_i == __b._M_i;
    514       return __ret;
    515     }
    516 
    517   template<typename _Cond>
    518     inline bool
    519     operator<(const throw_value_base<_Cond>& __a,
    520 	      const throw_value_base<_Cond>& __b)
    521     {
    522       typedef throw_value_base<_Cond> throw_value;
    523       throw_value::throw_conditionally();
    524       bool __ret = __a._M_i < __b._M_i;
    525       return __ret;
    526     }
    527 
    528   // Numeric algorithms instantiable types requirements.
    529   template<typename _Cond>
    530     inline throw_value_base<_Cond>
    531     operator+(const throw_value_base<_Cond>& __a,
    532 	      const throw_value_base<_Cond>& __b)
    533     {
    534       typedef throw_value_base<_Cond> throw_value;
    535       throw_value::throw_conditionally();
    536       throw_value __ret(__a._M_i + __b._M_i);
    537       return __ret;
    538     }
    539 
    540   template<typename _Cond>
    541     inline throw_value_base<_Cond>
    542     operator-(const throw_value_base<_Cond>& __a,
    543 	      const throw_value_base<_Cond>& __b)
    544     {
    545       typedef throw_value_base<_Cond> throw_value;
    546       throw_value::throw_conditionally();
    547       throw_value __ret(__a._M_i - __b._M_i);
    548       return __ret;
    549     }
    550 
    551   template<typename _Cond>
    552     inline throw_value_base<_Cond>
    553     operator*(const throw_value_base<_Cond>& __a,
    554 	      const throw_value_base<_Cond>& __b)
    555     {
    556       typedef throw_value_base<_Cond> throw_value;
    557       throw_value::throw_conditionally();
    558       throw_value __ret(__a._M_i * __b._M_i);
    559       return __ret;
    560     }
    561 
    562 
    563   /// Type throwing via limit condition.
    564   struct throw_value_limit : public throw_value_base<limit_condition>
    565   {
    566     typedef throw_value_base<limit_condition> base_type;
    567 
    568 #ifndef _GLIBCXX_IS_AGGREGATE
    569     throw_value_limit() { }
    570 
    571     throw_value_limit(const throw_value_limit& __other)
    572     : base_type(__other._M_i) { }
    573 
    574 #if __cplusplus >= 201103L
    575     throw_value_limit(throw_value_limit&&) = default;
    576 #endif
    577 
    578     explicit throw_value_limit(const std::size_t __i) : base_type(__i) { }
    579 #endif
    580 
    581     throw_value_limit&
    582     operator=(const throw_value_limit& __other)
    583     {
    584       base_type::operator=(__other);
    585       return *this;
    586     }
    587 
    588 #if __cplusplus >= 201103L
    589     throw_value_limit&
    590     operator=(throw_value_limit&&) = default;
    591 #endif
    592   };
    593 
    594   /// Type throwing via random condition.
    595   struct throw_value_random : public throw_value_base<random_condition>
    596   {
    597     typedef throw_value_base<random_condition> base_type;
    598 
    599 #ifndef _GLIBCXX_IS_AGGREGATE
    600     throw_value_random() { }
    601 
    602     throw_value_random(const throw_value_random& __other)
    603     : base_type(__other._M_i) { }
    604 
    605 #if __cplusplus >= 201103L
    606     throw_value_random(throw_value_random&&) = default;
    607 #endif
    608 
    609     explicit throw_value_random(const std::size_t __i) : base_type(__i) { }
    610 #endif
    611 
    612     throw_value_random&
    613     operator=(const throw_value_random& __other)
    614     {
    615       base_type::operator=(__other);
    616       return *this;
    617     }
    618 
    619 #if __cplusplus >= 201103L
    620     throw_value_random&
    621     operator=(throw_value_random&&) = default;
    622 #endif
    623   };
    624 
    625 
    626   /**
    627    *  @brief Allocator class with logging and exception generation control.
    628    * Intended to be used as an allocator_type in templatized code.
    629    *  @ingroup allocators
    630    *
    631    *  Note: Deallocate not allowed to throw.
    632    */
    633   template<typename _Tp, typename _Cond>
    634     class throw_allocator_base
    635     : public annotate_base, public _Cond
    636     {
    637     public:
    638       typedef size_t 				size_type;
    639       typedef ptrdiff_t 			difference_type;
    640       typedef _Tp 				value_type;
    641       typedef value_type* 			pointer;
    642       typedef const value_type* 		const_pointer;
    643       typedef value_type& 			reference;
    644       typedef const value_type& 		const_reference;
    645 
    646 #if __cplusplus >= 201103L
    647       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    648       // 2103. std::allocator propagate_on_container_move_assignment
    649       typedef std::true_type propagate_on_container_move_assignment;
    650 #endif
    651 
    652     private:
    653       typedef _Cond				condition_type;
    654 
    655       std::allocator<value_type> 		_M_allocator;
    656 
    657       using condition_type::throw_conditionally;
    658 
    659     public:
    660       size_type
    661       max_size() const _GLIBCXX_USE_NOEXCEPT
    662       { return _M_allocator.max_size(); }
    663 
    664       pointer
    665       address(reference __x) const _GLIBCXX_NOEXCEPT
    666       { return std::__addressof(__x); }
    667 
    668       const_pointer
    669       address(const_reference __x) const _GLIBCXX_NOEXCEPT
    670       { return std::__addressof(__x); }
    671 
    672       pointer
    673       allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
    674       {
    675 	if (__n > this->max_size())
    676 	  std::__throw_bad_alloc();
    677 
    678 	throw_conditionally();
    679 	pointer const a = _M_allocator.allocate(__n, hint);
    680 	insert(a, sizeof(value_type) * __n);
    681 	return a;
    682       }
    683 
    684 #if __cplusplus >= 201103L
    685       template<typename _Up, typename... _Args>
    686         void
    687         construct(_Up* __p, _Args&&... __args)
    688 	{ return _M_allocator.construct(__p, std::forward<_Args>(__args)...); }
    689 
    690       template<typename _Up>
    691         void
    692         destroy(_Up* __p)
    693         { _M_allocator.destroy(__p); }
    694 #else
    695       void
    696       construct(pointer __p, const value_type& val)
    697       { return _M_allocator.construct(__p, val); }
    698 
    699       void
    700       destroy(pointer __p)
    701       { _M_allocator.destroy(__p); }
    702 #endif
    703 
    704       void
    705       deallocate(pointer __p, size_type __n)
    706       {
    707 	erase(__p, sizeof(value_type) * __n);
    708 	_M_allocator.deallocate(__p, __n);
    709       }
    710 
    711       void
    712       check_allocated(pointer __p, size_type __n)
    713       {
    714 	size_type __t = sizeof(value_type) * __n;
    715 	annotate_base::check_allocated(__p, __t);
    716       }
    717 
    718       void
    719       check_allocated(size_type __n)
    720       { annotate_base::check_allocated(__n); }
    721   };
    722 
    723   template<typename _Tp, typename _Cond>
    724     inline bool
    725     operator==(const throw_allocator_base<_Tp, _Cond>&,
    726 	       const throw_allocator_base<_Tp, _Cond>&)
    727     { return true; }
    728 
    729   template<typename _Tp, typename _Cond>
    730     inline bool
    731     operator!=(const throw_allocator_base<_Tp, _Cond>&,
    732 	       const throw_allocator_base<_Tp, _Cond>&)
    733     { return false; }
    734 
    735   /// Allocator throwing via limit condition.
    736   template<typename _Tp>
    737     struct throw_allocator_limit
    738     : public throw_allocator_base<_Tp, limit_condition>
    739     {
    740       template<typename _Tp1>
    741 	struct rebind
    742 	{ typedef throw_allocator_limit<_Tp1> other; };
    743 
    744       throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
    745 
    746       throw_allocator_limit(const throw_allocator_limit&)
    747       _GLIBCXX_USE_NOEXCEPT { }
    748 
    749       template<typename _Tp1>
    750 	throw_allocator_limit(const throw_allocator_limit<_Tp1>&)
    751 	_GLIBCXX_USE_NOEXCEPT { }
    752 
    753       ~throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
    754     };
    755 
    756   /// Allocator throwing via random condition.
    757   template<typename _Tp>
    758     struct throw_allocator_random
    759     : public throw_allocator_base<_Tp, random_condition>
    760     {
    761       template<typename _Tp1>
    762 	struct rebind
    763 	{ typedef throw_allocator_random<_Tp1> other; };
    764 
    765       throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
    766 
    767       throw_allocator_random(const throw_allocator_random&)
    768       _GLIBCXX_USE_NOEXCEPT { }
    769 
    770       template<typename _Tp1>
    771 	throw_allocator_random(const throw_allocator_random<_Tp1>&)
    772 	_GLIBCXX_USE_NOEXCEPT { }
    773 
    774       ~throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
    775     };
    776 
    777 _GLIBCXX_END_NAMESPACE_VERSION
    778 } // namespace
    779 
    780 #if __cplusplus >= 201103L
    781 
    782 # include <bits/functional_hash.h>
    783 
    784 namespace std _GLIBCXX_VISIBILITY(default)
    785 {
    786   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
    787   template<>
    788     struct hash<__gnu_cxx::throw_value_limit>
    789     : public std::unary_function<__gnu_cxx::throw_value_limit, size_t>
    790     {
    791       size_t
    792       operator()(const __gnu_cxx::throw_value_limit& __val) const
    793       {
    794 	std::hash<std::size_t> __h;
    795 	size_t __result = __h(__val._M_i);
    796 	return __result;
    797       }
    798     };
    799 
    800   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
    801   template<>
    802     struct hash<__gnu_cxx::throw_value_random>
    803     : public std::unary_function<__gnu_cxx::throw_value_random, size_t>
    804     {
    805       size_t
    806       operator()(const __gnu_cxx::throw_value_random& __val) const
    807       {
    808 	std::hash<std::size_t> __h;
    809 	size_t __result = __h(__val._M_i);
    810 	return __result;
    811       }
    812     };
    813 } // end namespace std
    814 #endif
    815 
    816 #endif
    817