libstdc++
throw_allocator.h
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // Copyright (C) 2005-2013 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the terms
00007 // of the GNU General Public License as published by the Free Software
00008 // Foundation; either version 3, or (at your option) any later
00009 // version.
00010 
00011 // This library is distributed in the hope that it will be useful, but
00012 // WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
00026 
00027 // Permission to use, copy, modify, sell, and distribute this software
00028 // is hereby granted without fee, provided that the above copyright
00029 // notice appears in all copies, and that both that copyright notice
00030 // and this permission notice appear in supporting documentation. None
00031 // of the above authors, nor IBM Haifa Research Laboratories, make any
00032 // representation about the suitability of this software for any
00033 // purpose. It is provided "as is" without express or implied
00034 // warranty.
00035 
00036 /** @file ext/throw_allocator.h
00037  *  This file is a GNU extension to the Standard C++ Library.
00038  *
00039  *  Contains two exception-generating types (throw_value, throw_allocator)
00040  *  intended to be used as value and allocator types while testing
00041  *  exception safety in templatized containers and algorithms. The
00042  *  allocator has additional log and debug features. The exception
00043  *  generated is of type forced_exception_error.
00044  */
00045 
00046 #ifndef _THROW_ALLOCATOR_H
00047 #define _THROW_ALLOCATOR_H 1
00048 
00049 #include <cmath>
00050 #include <ctime>
00051 #include <map>
00052 #include <string>
00053 #include <ostream>
00054 #include <stdexcept>
00055 #include <utility>
00056 #include <bits/functexcept.h>
00057 #include <bits/move.h>
00058 #if __cplusplus >= 201103L
00059 # include <functional>
00060 # include <random>
00061 #else
00062 # include <tr1/functional>
00063 # include <tr1/random>
00064 #endif
00065 
00066 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
00067 {
00068 _GLIBCXX_BEGIN_NAMESPACE_VERSION
00069 
00070   /**
00071    *  @brief Thown by exception safety machinery.
00072    *  @ingroup exceptions
00073    */
00074   struct forced_error : public std::exception
00075   { };
00076 
00077   // Substitute for forced_error object when -fno-exceptions.
00078   inline void
00079   __throw_forced_error()
00080   { _GLIBCXX_THROW_OR_ABORT(forced_error()); }
00081 
00082   /**
00083    *  @brief Base class for checking address and label information
00084    *  about allocations. Create a std::map between the allocated
00085    *  address (void*) and a datum for annotations, which are a pair of
00086    *  numbers corresponding to label and allocated size.
00087    */
00088   struct annotate_base
00089   {
00090     annotate_base()
00091     {
00092       label();
00093       map();
00094     }
00095 
00096     static void
00097     set_label(size_t l)
00098     { label() = l; }
00099 
00100     static size_t
00101     get_label()
00102     { return label(); }
00103 
00104     void
00105     insert(void* p, size_t size)
00106     {
00107       if (!p)
00108     {
00109       std::string error("annotate_base::insert null insert!\n");
00110       log_to_string(error, make_entry(p, size));
00111       std::__throw_logic_error(error.c_str());
00112     }
00113 
00114       const_iterator found = map().find(p);
00115       if (found != map().end())
00116     {
00117       std::string error("annotate_base::insert double insert!\n");
00118       log_to_string(error, make_entry(p, size));
00119       log_to_string(error, *found);
00120       std::__throw_logic_error(error.c_str());
00121     }
00122 
00123       map().insert(make_entry(p, size));
00124     }
00125 
00126     void
00127     erase(void* p, size_t size)
00128     {
00129       check_allocated(p, size);
00130       map().erase(p);
00131     }
00132 
00133     // See if a particular address and allocation size has been saved.
00134     inline void
00135     check_allocated(void* p, size_t size)
00136     {
00137       const_iterator found = map().find(p);
00138       if (found == map().end())
00139     {
00140       std::string error("annotate_base::check_allocated by value "
00141                 "null erase!\n");
00142       log_to_string(error, make_entry(p, size));
00143       std::__throw_logic_error(error.c_str());
00144     }
00145 
00146       if (found->second.second != size)
00147     {
00148       std::string error("annotate_base::check_allocated by value "
00149                 "wrong-size erase!\n");
00150       log_to_string(error, make_entry(p, size));
00151       log_to_string(error, *found);
00152       std::__throw_logic_error(error.c_str());
00153     }
00154     }
00155 
00156     // See if a given label has been allocated.
00157     inline void
00158     check_allocated(size_t label)
00159     {
00160       const_iterator beg = map().begin();
00161       const_iterator end = map().end();
00162       std::string found;
00163       while (beg != end)
00164     {
00165       if (beg->second.first == label)
00166         log_to_string(found, *beg);
00167       ++beg;
00168     }
00169 
00170       if (!found.empty())
00171     {
00172       std::string error("annotate_base::check_allocated by label\n");
00173       error += found;
00174       std::__throw_logic_error(error.c_str());
00175     }
00176     }
00177 
00178   private:
00179     typedef std::pair<size_t, size_t>       data_type;
00180     typedef std::map<void*, data_type>      map_type;
00181     typedef map_type::value_type        entry_type;
00182     typedef map_type::const_iterator        const_iterator;
00183     typedef map_type::const_reference       const_reference;
00184 
00185     friend std::ostream&
00186     operator<<(std::ostream&, const annotate_base&);
00187 
00188     entry_type
00189     make_entry(void* p, size_t size)
00190     { return std::make_pair(p, data_type(get_label(), size)); }
00191 
00192     void
00193     log_to_string(std::string& s, const_reference ref) const
00194     {
00195       char buf[40];
00196       const char tab('\t');
00197       s += "label: ";
00198       unsigned long l = static_cast<unsigned long>(ref.second.first);
00199       __builtin_sprintf(buf, "%lu", l);
00200       s += buf;
00201       s += tab;
00202       s += "size: ";
00203       l = static_cast<unsigned long>(ref.second.second);
00204       __builtin_sprintf(buf, "%lu", l);
00205       s += buf;
00206       s += tab;
00207       s += "address: ";
00208       __builtin_sprintf(buf, "%p", ref.first);
00209       s += buf;
00210       s += '\n';
00211     }
00212 
00213     static size_t&
00214     label()
00215     {
00216       static size_t _S_label(std::numeric_limits<size_t>::max());
00217       return _S_label;
00218     }
00219 
00220     static map_type&
00221     map()
00222     {
00223       static map_type _S_map;
00224       return _S_map;
00225     }
00226   };
00227 
00228   inline std::ostream&
00229   operator<<(std::ostream& os, const annotate_base& __b)
00230   {
00231     std::string error;
00232     typedef annotate_base base_type;
00233     base_type::const_iterator beg = __b.map().begin();
00234     base_type::const_iterator end = __b.map().end();
00235     for (; beg != end; ++beg)
00236       __b.log_to_string(error, *beg);
00237     return os << error;
00238   }
00239 
00240 
00241   /**
00242    *  @brief Base struct for condition policy.
00243    *
00244    * Requires a public member function with the signature
00245    * void throw_conditionally()
00246    */
00247   struct condition_base
00248   {
00249     virtual ~condition_base() { };
00250   };
00251 
00252 
00253   /**
00254    *  @brief Base class for incremental control and throw.
00255    */
00256   struct limit_condition : public condition_base
00257   {
00258     // Scope-level adjustor objects: set limit for throw at the
00259     // beginning of a scope block, and restores to previous limit when
00260     // object is destroyed on exiting the block.
00261     struct adjustor_base
00262     {
00263     private:
00264       const size_t _M_orig;
00265 
00266     public:
00267       adjustor_base() : _M_orig(limit()) { }
00268 
00269       virtual
00270       ~adjustor_base() { set_limit(_M_orig); }
00271     };
00272 
00273     /// Never enter the condition.
00274     struct never_adjustor : public adjustor_base
00275     {
00276       never_adjustor() { set_limit(std::numeric_limits<size_t>::max()); }
00277     };
00278 
00279     /// Always enter the condition.
00280     struct always_adjustor : public adjustor_base
00281     {
00282       always_adjustor() { set_limit(count()); }
00283     };
00284 
00285     /// Enter the nth condition.
00286     struct limit_adjustor : public adjustor_base
00287     {
00288       limit_adjustor(const size_t __l) { set_limit(__l); }
00289     };
00290 
00291     // Increment _S_count every time called.
00292     // If _S_count matches the limit count, throw.
00293     static void
00294     throw_conditionally()
00295     {
00296       if (count() == limit())
00297     __throw_forced_error();
00298       ++count();
00299     }
00300 
00301     static size_t&
00302     count()
00303     {
00304       static size_t _S_count(0);
00305       return _S_count;
00306     }
00307 
00308     static size_t&
00309     limit()
00310     {
00311       static size_t _S_limit(std::numeric_limits<size_t>::max());
00312       return _S_limit;
00313     }
00314 
00315     // Zero the throw counter, set limit to argument.
00316     static void
00317     set_limit(const size_t __l)
00318     {
00319       limit() = __l;
00320       count() = 0;
00321     }
00322   };
00323 
00324 
00325   /**
00326    *  @brief Base class for random probability control and throw.
00327    */
00328   struct random_condition : public condition_base
00329   {
00330     // Scope-level adjustor objects: set probability for throw at the
00331     // beginning of a scope block, and restores to previous
00332     // probability when object is destroyed on exiting the block.
00333     struct adjustor_base
00334     {
00335     private:
00336       const double _M_orig;
00337 
00338     public:
00339       adjustor_base() : _M_orig(probability()) { }
00340 
00341       virtual ~adjustor_base()
00342       { set_probability(_M_orig); }
00343     };
00344 
00345     /// Group condition.
00346     struct group_adjustor : public adjustor_base
00347     {
00348       group_adjustor(size_t size)
00349       { set_probability(1 - std::pow(double(1 - probability()),
00350                      double(0.5 / (size + 1))));
00351       }
00352     };
00353 
00354     /// Never enter the condition.
00355     struct never_adjustor : public adjustor_base
00356     {
00357       never_adjustor() { set_probability(0); }
00358     };
00359 
00360     /// Always enter the condition.
00361     struct always_adjustor : public adjustor_base
00362     {
00363       always_adjustor() { set_probability(1); }
00364     };
00365 
00366     random_condition()
00367     {
00368       probability();
00369       engine();
00370     }
00371 
00372     static void
00373     set_probability(double __p)
00374     { probability() = __p; }
00375 
00376     static void
00377     throw_conditionally()
00378     {
00379       if (generate() < probability())
00380     __throw_forced_error();
00381     }
00382 
00383     void
00384     seed(unsigned long __s)
00385     { engine().seed(__s); }
00386 
00387   private:
00388 #if __cplusplus >= 201103L
00389     typedef std::uniform_real_distribution<double>  distribution_type;
00390     typedef std::mt19937                engine_type;
00391 #else
00392     typedef std::tr1::uniform_real<double>      distribution_type;
00393     typedef std::tr1::mt19937               engine_type;
00394 #endif
00395 
00396     static double
00397     generate()
00398     {
00399 #if __cplusplus >= 201103L
00400       const distribution_type distribution(0, 1);
00401       static auto generator = std::bind(distribution, engine());
00402 #else
00403       // Use variate_generator to get normalized results.
00404       typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t;
00405       distribution_type distribution(0, 1);
00406       static gen_t generator(engine(), distribution);
00407 #endif
00408 
00409       double random = generator();
00410       if (random < distribution.min() || random > distribution.max())
00411     {
00412       std::string __s("random_condition::generate");
00413       __s += "\n";
00414       __s += "random number generated is: ";
00415       char buf[40];
00416       __builtin_sprintf(buf, "%f", random);
00417       __s += buf;
00418       std::__throw_out_of_range(__s.c_str());
00419     }
00420 
00421       return random;
00422     }
00423 
00424     static double&
00425     probability()
00426     {
00427       static double _S_p;
00428       return _S_p;
00429     }
00430 
00431     static engine_type&
00432     engine()
00433     {
00434       static engine_type _S_e;
00435       return _S_e;
00436     }
00437   };
00438 
00439 
00440   /**
00441    *  @brief Class with exception generation control. Intended to be
00442    *  used as a value_type in templatized code.
00443    *
00444    *  Note: Destructor not allowed to throw.
00445    */
00446   template<typename _Cond>
00447     struct throw_value_base : public _Cond
00448     {
00449       typedef _Cond                 condition_type;
00450 
00451       using condition_type::throw_conditionally;
00452 
00453       std::size_t                   _M_i;
00454 
00455 #ifndef _GLIBCXX_IS_AGGREGATE
00456       throw_value_base() : _M_i(0)
00457       { throw_conditionally(); }
00458 
00459       throw_value_base(const throw_value_base& __v) : _M_i(__v._M_i)
00460       { throw_conditionally(); }
00461 
00462 #if __cplusplus >= 201103L
00463       // Shall not throw.
00464       throw_value_base(throw_value_base&&) = default;
00465 #endif
00466 
00467       explicit throw_value_base(const std::size_t __i) : _M_i(__i)
00468       { throw_conditionally(); }
00469 #endif
00470 
00471       throw_value_base&
00472       operator=(const throw_value_base& __v)
00473       {
00474     throw_conditionally();
00475     _M_i = __v._M_i;
00476     return *this;
00477       }
00478 
00479 #if __cplusplus >= 201103L
00480       // Shall not throw.
00481       throw_value_base&
00482       operator=(throw_value_base&&) = default;
00483 #endif
00484 
00485       throw_value_base&
00486       operator++()
00487       {
00488     throw_conditionally();
00489     ++_M_i;
00490     return *this;
00491       }
00492     };
00493 
00494   template<typename _Cond>
00495     inline void
00496     swap(throw_value_base<_Cond>& __a, throw_value_base<_Cond>& __b)
00497     {
00498       typedef throw_value_base<_Cond> throw_value;
00499       throw_value::throw_conditionally();
00500       throw_value orig(__a);
00501       __a = __b;
00502       __b = orig;
00503     }
00504 
00505   // General instantiable types requirements.
00506   template<typename _Cond>
00507     inline bool
00508     operator==(const throw_value_base<_Cond>& __a,
00509            const throw_value_base<_Cond>& __b)
00510     {
00511       typedef throw_value_base<_Cond> throw_value;
00512       throw_value::throw_conditionally();
00513       bool __ret = __a._M_i == __b._M_i;
00514       return __ret;
00515     }
00516 
00517   template<typename _Cond>
00518     inline bool
00519     operator<(const throw_value_base<_Cond>& __a,
00520           const throw_value_base<_Cond>& __b)
00521     {
00522       typedef throw_value_base<_Cond> throw_value;
00523       throw_value::throw_conditionally();
00524       bool __ret = __a._M_i < __b._M_i;
00525       return __ret;
00526     }
00527 
00528   // Numeric algorithms instantiable types requirements.
00529   template<typename _Cond>
00530     inline throw_value_base<_Cond>
00531     operator+(const throw_value_base<_Cond>& __a,
00532           const throw_value_base<_Cond>& __b)
00533     {
00534       typedef throw_value_base<_Cond> throw_value;
00535       throw_value::throw_conditionally();
00536       throw_value __ret(__a._M_i + __b._M_i);
00537       return __ret;
00538     }
00539 
00540   template<typename _Cond>
00541     inline throw_value_base<_Cond>
00542     operator-(const throw_value_base<_Cond>& __a,
00543           const throw_value_base<_Cond>& __b)
00544     {
00545       typedef throw_value_base<_Cond> throw_value;
00546       throw_value::throw_conditionally();
00547       throw_value __ret(__a._M_i - __b._M_i);
00548       return __ret;
00549     }
00550 
00551   template<typename _Cond>
00552     inline throw_value_base<_Cond>
00553     operator*(const throw_value_base<_Cond>& __a,
00554           const throw_value_base<_Cond>& __b)
00555     {
00556       typedef throw_value_base<_Cond> throw_value;
00557       throw_value::throw_conditionally();
00558       throw_value __ret(__a._M_i * __b._M_i);
00559       return __ret;
00560     }
00561 
00562 
00563   /// Type throwing via limit condition.
00564   struct throw_value_limit : public throw_value_base<limit_condition>
00565   {
00566     typedef throw_value_base<limit_condition> base_type;
00567 
00568 #ifndef _GLIBCXX_IS_AGGREGATE
00569     throw_value_limit() { }
00570 
00571     throw_value_limit(const throw_value_limit& __other)
00572     : base_type(__other._M_i) { }
00573 
00574 #if __cplusplus >= 201103L
00575     throw_value_limit(throw_value_limit&&) = default;
00576 #endif
00577 
00578     explicit throw_value_limit(const std::size_t __i) : base_type(__i) { }
00579 #endif
00580 
00581     throw_value_limit&
00582     operator=(const throw_value_limit& __other)
00583     {
00584       base_type::operator=(__other);
00585       return *this;
00586     }
00587 
00588 #if __cplusplus >= 201103L
00589     throw_value_limit&
00590     operator=(throw_value_limit&&) = default;
00591 #endif
00592   };
00593 
00594   /// Type throwing via random condition.
00595   struct throw_value_random : public throw_value_base<random_condition>
00596   {
00597     typedef throw_value_base<random_condition> base_type;
00598 
00599 #ifndef _GLIBCXX_IS_AGGREGATE
00600     throw_value_random() { }
00601 
00602     throw_value_random(const throw_value_random& __other)
00603     : base_type(__other._M_i) { }
00604 
00605 #if __cplusplus >= 201103L
00606     throw_value_random(throw_value_random&&) = default;
00607 #endif
00608 
00609     explicit throw_value_random(const std::size_t __i) : base_type(__i) { }
00610 #endif
00611 
00612     throw_value_random&
00613     operator=(const throw_value_random& __other)
00614     {
00615       base_type::operator=(__other);
00616       return *this;
00617     }
00618 
00619 #if __cplusplus >= 201103L
00620     throw_value_random&
00621     operator=(throw_value_random&&) = default;
00622 #endif
00623   };
00624 
00625 
00626   /**
00627    *  @brief Allocator class with logging and exception generation control.
00628    * Intended to be used as an allocator_type in templatized code.
00629    *  @ingroup allocators
00630    *
00631    *  Note: Deallocate not allowed to throw.
00632    */
00633   template<typename _Tp, typename _Cond>
00634     class throw_allocator_base
00635     : public annotate_base, public _Cond
00636     {
00637     public:
00638       typedef size_t                size_type;
00639       typedef ptrdiff_t             difference_type;
00640       typedef _Tp               value_type;
00641       typedef value_type*           pointer;
00642       typedef const value_type*         const_pointer;
00643       typedef value_type&           reference;
00644       typedef const value_type&         const_reference;
00645 
00646 #if __cplusplus >= 201103L
00647       // _GLIBCXX_RESOLVE_LIB_DEFECTS
00648       // 2103. std::allocator propagate_on_container_move_assignment
00649       typedef std::true_type propagate_on_container_move_assignment;
00650 #endif
00651 
00652     private:
00653       typedef _Cond             condition_type;
00654 
00655       std::allocator<value_type>        _M_allocator;
00656 
00657       using condition_type::throw_conditionally;
00658 
00659     public:
00660       size_type
00661       max_size() const _GLIBCXX_USE_NOEXCEPT
00662       { return _M_allocator.max_size(); }
00663 
00664       pointer
00665       address(reference __x) const _GLIBCXX_NOEXCEPT
00666       { return std::__addressof(__x); }
00667 
00668       const_pointer
00669       address(const_reference __x) const _GLIBCXX_NOEXCEPT
00670       { return std::__addressof(__x); }
00671 
00672       pointer
00673       allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
00674       {
00675     if (__n > this->max_size())
00676       std::__throw_bad_alloc();
00677 
00678     throw_conditionally();
00679     pointer const a = _M_allocator.allocate(__n, hint);
00680     insert(a, sizeof(value_type) * __n);
00681     return a;
00682       }
00683 
00684 #if __cplusplus >= 201103L
00685       template<typename _Up, typename... _Args>
00686         void
00687         construct(_Up* __p, _Args&&... __args)
00688     { return _M_allocator.construct(__p, std::forward<_Args>(__args)...); }
00689 
00690       template<typename _Up>
00691         void 
00692         destroy(_Up* __p)
00693         { _M_allocator.destroy(__p); }
00694 #else
00695       void
00696       construct(pointer __p, const value_type& val)
00697       { return _M_allocator.construct(__p, val); }
00698 
00699       void
00700       destroy(pointer __p)
00701       { _M_allocator.destroy(__p); }
00702 #endif
00703 
00704       void
00705       deallocate(pointer __p, size_type __n)
00706       {
00707     erase(__p, sizeof(value_type) * __n);
00708     _M_allocator.deallocate(__p, __n);
00709       }
00710 
00711       void
00712       check_allocated(pointer __p, size_type __n)
00713       {
00714     size_type __t = sizeof(value_type) * __n;
00715     annotate_base::check_allocated(__p, __t);
00716       }
00717 
00718       void
00719       check_allocated(size_type __n)
00720       { annotate_base::check_allocated(__n); }
00721   };
00722 
00723   template<typename _Tp, typename _Cond>
00724     inline bool
00725     operator==(const throw_allocator_base<_Tp, _Cond>&,
00726            const throw_allocator_base<_Tp, _Cond>&)
00727     { return true; }
00728 
00729   template<typename _Tp, typename _Cond>
00730     inline bool
00731     operator!=(const throw_allocator_base<_Tp, _Cond>&,
00732            const throw_allocator_base<_Tp, _Cond>&)
00733     { return false; }
00734 
00735   /// Allocator throwing via limit condition.
00736   template<typename _Tp>
00737     struct throw_allocator_limit
00738     : public throw_allocator_base<_Tp, limit_condition>
00739     {
00740       template<typename _Tp1>
00741     struct rebind
00742     { typedef throw_allocator_limit<_Tp1> other; };
00743 
00744       throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
00745 
00746       throw_allocator_limit(const throw_allocator_limit&)
00747       _GLIBCXX_USE_NOEXCEPT { }
00748 
00749       template<typename _Tp1>
00750     throw_allocator_limit(const throw_allocator_limit<_Tp1>&)
00751     _GLIBCXX_USE_NOEXCEPT { }
00752 
00753       ~throw_allocator_limit() _GLIBCXX_USE_NOEXCEPT { }
00754     };
00755 
00756   /// Allocator throwing via random condition.
00757   template<typename _Tp>
00758     struct throw_allocator_random
00759     : public throw_allocator_base<_Tp, random_condition>
00760     {
00761       template<typename _Tp1>
00762     struct rebind
00763     { typedef throw_allocator_random<_Tp1> other; };
00764 
00765       throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
00766 
00767       throw_allocator_random(const throw_allocator_random&)
00768       _GLIBCXX_USE_NOEXCEPT { }
00769 
00770       template<typename _Tp1>
00771     throw_allocator_random(const throw_allocator_random<_Tp1>&)
00772     _GLIBCXX_USE_NOEXCEPT { }
00773 
00774       ~throw_allocator_random() _GLIBCXX_USE_NOEXCEPT { }
00775     };
00776 
00777 _GLIBCXX_END_NAMESPACE_VERSION
00778 } // namespace
00779 
00780 #if __cplusplus >= 201103L
00781 
00782 # include <bits/functional_hash.h>
00783 
00784 namespace std _GLIBCXX_VISIBILITY(default)
00785 {
00786   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
00787   template<>
00788     struct hash<__gnu_cxx::throw_value_limit>
00789     : public std::unary_function<__gnu_cxx::throw_value_limit, size_t>
00790     {
00791       size_t
00792       operator()(const __gnu_cxx::throw_value_limit& __val) const
00793       {
00794     std::hash<std::size_t> __h;
00795     size_t __result = __h(__val._M_i);
00796     return __result;
00797       }
00798     };
00799 
00800   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
00801   template<>
00802     struct hash<__gnu_cxx::throw_value_random>
00803     : public std::unary_function<__gnu_cxx::throw_value_random, size_t>
00804     {
00805       size_t
00806       operator()(const __gnu_cxx::throw_value_random& __val) const
00807       {
00808     std::hash<std::size_t> __h;
00809     size_t __result = __h(__val._M_i);
00810     return __result;
00811       }
00812     };
00813 } // end namespace std
00814 #endif
00815 
00816 #endif