libstdc++
|
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