throw_allocator.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // Copyright (C) 2005, 2006, 2007, 2008, 2009 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 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00059 # include <functional>
00060 # include <random>
00061 #else
00062 # include <tr1/functional>
00063 # include <tr1/random>
00064 #endif
00065 
00066 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
00067 
00068   /**
00069    *  @brief Thown by exception safety machinery.
00070    *  @ingroup exceptions
00071    */
00072   struct forced_error : public std::exception
00073   { };
00074 
00075   // Substitute for forced_error object when -fno-exceptions.
00076   inline void
00077   __throw_forced_error()
00078   {
00079 #if __EXCEPTIONS
00080     throw forced_error();
00081 #else
00082     __builtin_abort();
00083 #endif
00084   }
00085 
00086 
00087   /**
00088    *  @brief Base class for checking address and label information
00089    *  about allocations. Create a std::map between the allocated
00090    *  address (void*) and a datum for annotations, which are a pair of
00091    *  numbers corresponding to label and allocated size.
00092    */
00093   struct annotate_base
00094   {
00095     annotate_base()
00096     {
00097       label();
00098       map();
00099     }
00100 
00101     static void
00102     set_label(size_t l)
00103     { label() = l; }
00104 
00105     static size_t
00106     get_label()
00107     { return label(); }
00108 
00109     void
00110     insert(void* p, size_t size)
00111     {
00112       if (p == NULL)
00113     {
00114       std::string error("annotate_base::insert null insert!\n");
00115       log_to_string(error, make_entry(p, size));
00116       std::__throw_logic_error(error.c_str());
00117     }
00118 
00119       const_iterator found = map().find(p);
00120       if (found != map().end())
00121     {
00122       std::string error("annotate_base::insert double insert!\n");
00123       log_to_string(error, make_entry(p, size));
00124       log_to_string(error, *found);
00125       std::__throw_logic_error(error.c_str());
00126     }
00127 
00128       map().insert(make_entry(p, size));
00129     }
00130 
00131     void
00132     erase(void* p, size_t size)
00133     {
00134       check_allocated(p, size);
00135       map().erase(p);
00136     }
00137 
00138     // See if a particular address and allocation size has been saved.
00139     inline void
00140     check_allocated(void* p, size_t size)
00141     {
00142       const_iterator found = map().find(p);
00143       if (found == map().end())
00144     {
00145       std::string error("annotate_base::check_allocated by value "
00146                 "null erase!\n");
00147       log_to_string(error, make_entry(p, size));
00148       std::__throw_logic_error(error.c_str());
00149     }
00150 
00151       if (found->second.second != size)
00152     {
00153       std::string error("annotate_base::check_allocated by value "
00154                 "wrong-size erase!\n");
00155       log_to_string(error, make_entry(p, size));
00156       log_to_string(error, *found);
00157       std::__throw_logic_error(error.c_str());
00158     }
00159     }
00160 
00161     // See if a given label has been allocated.
00162     inline void
00163     check_allocated(size_t label)
00164     {
00165       const_iterator beg = map().begin();
00166       const_iterator end = map().end();
00167       std::string found;
00168       while (beg != end)
00169     {
00170       if (beg->second.first == label)
00171         log_to_string(found, *beg);
00172       ++beg;
00173     }
00174 
00175       if (!found.empty())
00176     {
00177       std::string error("annotate_base::check_allocated by label\n");
00178       error += found;
00179       std::__throw_logic_error(error.c_str());
00180     }
00181     }
00182 
00183   private:
00184     typedef std::pair<size_t, size_t>       data_type;
00185     typedef std::map<void*, data_type>      map_type;
00186     typedef map_type::value_type        entry_type;
00187     typedef map_type::const_iterator        const_iterator;
00188     typedef map_type::const_reference       const_reference;
00189 
00190     friend std::ostream&
00191     operator<<(std::ostream&, const annotate_base&);
00192 
00193     entry_type
00194     make_entry(void* p, size_t size)
00195     { return std::make_pair(p, data_type(get_label(), size)); }
00196 
00197     void
00198     log_to_string(std::string& s, const_reference ref) const
00199     {
00200       char buf[40];
00201       const char tab('\t');
00202       s += "label: ";
00203       unsigned long l = static_cast<unsigned long>(ref.second.first);
00204       __builtin_sprintf(buf, "%lu", l);
00205       s += buf;
00206       s += tab;
00207       s += "size: ";
00208       l = static_cast<unsigned long>(ref.second.second);
00209       __builtin_sprintf(buf, "%lu", l);
00210       s += buf;
00211       s += tab;
00212       s += "address: ";
00213       __builtin_sprintf(buf, "%p", ref.first);
00214       s += buf;
00215       s += '\n';
00216     }
00217 
00218     static size_t&
00219     label()
00220     {
00221       static size_t _S_label(std::numeric_limits<size_t>::max());
00222       return _S_label;
00223     }
00224 
00225     static map_type&
00226     map()
00227     {
00228       static map_type _S_map;
00229       return _S_map;
00230     }
00231   };
00232 
00233   inline std::ostream&
00234   operator<<(std::ostream& os, const annotate_base& __b)
00235   {
00236     std::string error;
00237     typedef annotate_base base_type;
00238     base_type::const_iterator beg = __b.map().begin();
00239     base_type::const_iterator end = __b.map().end();
00240     for (; beg != end; ++beg)
00241       __b.log_to_string(error, *beg);
00242     return os << error;
00243   }
00244 
00245 
00246   /**
00247    *  @brief Base struct for condition policy.
00248    *
00249    * Requires a public member function with the signature
00250    * void throw_conditionally()
00251    */
00252   struct condition_base
00253   {
00254     virtual ~condition_base() { };
00255   };
00256 
00257 
00258   /**
00259    *  @brief Base class for incremental control and throw.
00260    */
00261   struct limit_condition : public condition_base
00262   {
00263     // Scope-level adjustor objects: set limit for throw at the
00264     // beginning of a scope block, and restores to previous limit when
00265     // object is destroyed on exiting the block.
00266     struct adjustor_base
00267     {
00268     private:
00269       const size_t _M_orig;
00270 
00271     public:
00272       adjustor_base() : _M_orig(limit()) { }
00273 
00274       virtual
00275       ~adjustor_base() { set_limit(_M_orig); }
00276     };
00277 
00278     /// Never enter the condition.
00279     struct never_adjustor : public adjustor_base
00280     {
00281       never_adjustor() { set_limit(std::numeric_limits<size_t>::max()); }
00282     };
00283 
00284     /// Always enter the condition.
00285     struct always_adjustor : public adjustor_base
00286     {
00287       always_adjustor() { set_limit(count()); }
00288     };
00289 
00290     /// Enter the nth condition.
00291     struct limit_adjustor : public adjustor_base
00292     {
00293       limit_adjustor(const size_t __l) { set_limit(__l); }
00294     };
00295 
00296     // Increment _S_count every time called.
00297     // If _S_count matches the limit count, throw.
00298     static void
00299     throw_conditionally()
00300     {
00301       if (count() == limit())
00302     __throw_forced_error();
00303       ++count();
00304     }
00305 
00306     static size_t&
00307     count()
00308     {
00309       static size_t _S_count(0);
00310       return _S_count;
00311     }
00312 
00313     static size_t&
00314     limit()
00315     {
00316       static size_t _S_limit(std::numeric_limits<size_t>::max());
00317       return _S_limit;
00318     }
00319 
00320     // Zero the throw counter, set limit to argument.
00321     static void
00322     set_limit(const size_t __l)
00323     {
00324       limit() = __l;
00325       count() = 0;
00326     }
00327   };
00328 
00329 
00330   /**
00331    *  @brief Base class for random probability control and throw.
00332    */
00333   struct random_condition : public condition_base
00334   {
00335     // Scope-level adjustor objects: set probability for throw at the
00336     // beginning of a scope block, and restores to previous
00337     // probability when object is destroyed on exiting the block.
00338     struct adjustor_base
00339     {
00340     private:
00341       const double _M_orig;
00342 
00343     public:
00344       adjustor_base() : _M_orig(probability()) { }
00345 
00346       virtual ~adjustor_base()
00347       { set_probability(_M_orig); }
00348     };
00349 
00350     /// Group condition.
00351     struct group_adjustor : public adjustor_base
00352     {
00353       group_adjustor(size_t size)
00354       { set_probability(1 - std::pow(double(1 - probability()),
00355                      double(0.5 / (size + 1))));
00356       }
00357     };
00358 
00359     /// Never enter the condition.
00360     struct never_adjustor : public adjustor_base
00361     {
00362       never_adjustor() { set_probability(0); }
00363     };
00364 
00365     /// Always enter the condition.
00366     struct always_adjustor : public adjustor_base
00367     {
00368       always_adjustor() { set_probability(1); }
00369     };
00370 
00371     random_condition()
00372     {
00373       probability();
00374       engine();
00375     }
00376 
00377     static void
00378     set_probability(double __p)
00379     { probability() = __p; }
00380 
00381     static void
00382     throw_conditionally()
00383     {
00384       if (generate() < probability())
00385     __throw_forced_error();
00386     }
00387 
00388     void
00389     seed(unsigned long __s)
00390     { engine().seed(__s); }
00391 
00392   private:
00393 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00394     typedef std::uniform_real_distribution<double>  distribution_type;
00395     typedef std::mt19937                engine_type;
00396 #else
00397     typedef std::tr1::uniform_real<double>      distribution_type;
00398     typedef std::tr1::mt19937               engine_type;
00399 #endif
00400 
00401     static double
00402     generate()
00403     {
00404 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00405       const distribution_type distribution(0, 1);
00406       static auto generator = std::bind(distribution, engine());
00407 #else
00408       // Use variate_generator to get normalized results.
00409       typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t;
00410       distribution_type distribution(0, 1);
00411       static gen_t generator(engine(), distribution);
00412 #endif
00413 
00414       double random = generator();
00415       if (random < distribution.min() || random > distribution.max())
00416     {
00417       std::string __s("random_condition::generate");
00418       __s += "\n";
00419       __s += "random number generated is: ";
00420       char buf[40];
00421       __builtin_sprintf(buf, "%f", random);
00422       __s += buf;
00423       std::__throw_out_of_range(__s.c_str());
00424     }
00425 
00426       return random;
00427     }
00428 
00429     static double&
00430     probability()
00431     {
00432       static double _S_p;
00433       return _S_p;
00434     }
00435 
00436     static engine_type&
00437     engine()
00438     {
00439       static engine_type _S_e;
00440       return _S_e;
00441     }
00442   };
00443 
00444 
00445   /**
00446    *  @brief Class with exception generation control. Intended to be
00447    *  used as a value_type in templatized code.
00448    *
00449    *  Note: Destructor not allowed to throw.
00450    */
00451   template<typename _Cond>
00452     struct throw_value_base : public _Cond
00453     {
00454       typedef _Cond                 condition_type;
00455 
00456       using condition_type::throw_conditionally;
00457 
00458       std::size_t                   _M_i;
00459 
00460 #ifndef _GLIBCXX_IS_AGGREGATE
00461       throw_value_base() : _M_i(0)
00462       { throw_conditionally(); }
00463 
00464       throw_value_base(const throw_value_base& __v) : _M_i(__v._M_i)
00465       { throw_conditionally(); }
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       throw_value_base&
00480       operator++()
00481       {
00482     throw_conditionally();
00483     ++_M_i;
00484     return *this;
00485       }
00486     };
00487 
00488   template<typename _Cond>
00489     inline void
00490     swap(throw_value_base<_Cond>& __a, throw_value_base<_Cond>& __b)
00491     {
00492       typedef throw_value_base<_Cond> throw_value;
00493       throw_value::throw_conditionally();
00494       throw_value orig(__a);
00495       __a = __b;
00496       __b = orig;
00497     }
00498 
00499   // General instantiable types requirements.
00500   template<typename _Cond>
00501     inline bool
00502     operator==(const throw_value_base<_Cond>& __a,
00503            const throw_value_base<_Cond>& __b)
00504     {
00505       typedef throw_value_base<_Cond> throw_value;
00506       throw_value::throw_conditionally();
00507       bool __ret = __a._M_i == __b._M_i;
00508       return __ret;
00509     }
00510 
00511   template<typename _Cond>
00512     inline bool
00513     operator<(const throw_value_base<_Cond>& __a,
00514           const throw_value_base<_Cond>& __b)
00515     {
00516       typedef throw_value_base<_Cond> throw_value;
00517       throw_value::throw_conditionally();
00518       bool __ret = __a._M_i < __b._M_i;
00519       return __ret;
00520     }
00521 
00522   // Numeric algorithms instantiable types requirements.
00523   template<typename _Cond>
00524     inline throw_value_base<_Cond>
00525     operator+(const throw_value_base<_Cond>& __a,
00526           const throw_value_base<_Cond>& __b)
00527     {
00528       typedef throw_value_base<_Cond> throw_value;
00529       throw_value::throw_conditionally();
00530       throw_value __ret(__a._M_i + __b._M_i);
00531       return __ret;
00532     }
00533 
00534   template<typename _Cond>
00535     inline throw_value_base<_Cond>
00536     operator-(const throw_value_base<_Cond>& __a,
00537           const throw_value_base<_Cond>& __b)
00538     {
00539       typedef throw_value_base<_Cond> throw_value;
00540       throw_value::throw_conditionally();
00541       throw_value __ret(__a._M_i - __b._M_i);
00542       return __ret;
00543     }
00544 
00545   template<typename _Cond>
00546     inline throw_value_base<_Cond>
00547     operator*(const throw_value_base<_Cond>& __a,
00548           const throw_value_base<_Cond>& __b)
00549     {
00550       typedef throw_value_base<_Cond> throw_value;
00551       throw_value::throw_conditionally();
00552       throw_value __ret(__a._M_i * __b._M_i);
00553       return __ret;
00554     }
00555 
00556 
00557   /// Type throwing via limit condition.
00558   struct throw_value_limit : public throw_value_base<limit_condition>
00559   {
00560     typedef throw_value_base<limit_condition> base_type;
00561 
00562 #ifndef _GLIBCXX_IS_AGGREGATE
00563     throw_value_limit() { }
00564 
00565     throw_value_limit(const throw_value_limit& __other)
00566     : base_type(__other._M_i) { }
00567 
00568     explicit throw_value_limit(const std::size_t __i) : base_type(__i) { }
00569 #endif
00570   };
00571 
00572   /// Type throwing via random condition.
00573   struct throw_value_random : public throw_value_base<random_condition>
00574   {
00575     typedef throw_value_base<random_condition> base_type;
00576 
00577 #ifndef _GLIBCXX_IS_AGGREGATE
00578     throw_value_random() { }
00579 
00580     throw_value_random(const throw_value_random& __other)
00581     : base_type(__other._M_i) { }
00582 
00583 
00584     explicit throw_value_random(const std::size_t __i) : base_type(__i) { }
00585 #endif
00586   };
00587 
00588 
00589   /**
00590    *  @brief Allocator class with logging and exception generation control.
00591    * Intended to be used as an allocator_type in templatized code.
00592    *  @ingroup allocators
00593    *
00594    *  Note: Deallocate not allowed to throw.
00595    */
00596   template<typename _Tp, typename _Cond>
00597     class throw_allocator_base
00598     : public annotate_base, public _Cond
00599     {
00600     public:
00601       typedef size_t                size_type;
00602       typedef ptrdiff_t             difference_type;
00603       typedef _Tp               value_type;
00604       typedef value_type*           pointer;
00605       typedef const value_type*         const_pointer;
00606       typedef value_type&           reference;
00607       typedef const value_type&         const_reference;
00608 
00609     private:
00610       typedef _Cond             condition_type;
00611 
00612       std::allocator<value_type>        _M_allocator;
00613 
00614       using condition_type::throw_conditionally;
00615 
00616     public:
00617       size_type
00618       max_size() const throw()
00619       { return _M_allocator.max_size(); }
00620 
00621       pointer
00622       allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
00623       {
00624     if (__n > this->max_size())
00625       std::__throw_bad_alloc();
00626 
00627     throw_conditionally();
00628     pointer const a = _M_allocator.allocate(__n, hint);
00629     insert(a, sizeof(value_type) * __n);
00630     return a;
00631       }
00632 
00633       void
00634       construct(pointer __p, const value_type& val)
00635       { return _M_allocator.construct(__p, val); }
00636 
00637 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00638       template<typename... _Args>
00639     void
00640     construct(pointer __p, _Args&&... __args)
00641     { return _M_allocator.construct(__p, std::forward<_Args>(__args)...); }
00642 #endif
00643 
00644       void
00645       destroy(pointer __p)
00646       { _M_allocator.destroy(__p); }
00647 
00648       void
00649       deallocate(pointer __p, size_type __n)
00650       {
00651     erase(__p, sizeof(value_type) * __n);
00652     _M_allocator.deallocate(__p, __n);
00653       }
00654 
00655       void
00656       check_allocated(pointer __p, size_type __n)
00657       {
00658     size_type __t = sizeof(value_type) * __n;
00659     annotate_base::check_allocated(__p, __t);
00660       }
00661 
00662       void
00663       check_allocated(size_type __n)
00664       { annotate_base::check_allocated(__n); }
00665   };
00666 
00667   template<typename _Tp, typename _Cond>
00668     inline bool
00669     operator==(const throw_allocator_base<_Tp, _Cond>&,
00670            const throw_allocator_base<_Tp, _Cond>&)
00671     { return true; }
00672 
00673   template<typename _Tp, typename _Cond>
00674     inline bool
00675     operator!=(const throw_allocator_base<_Tp, _Cond>&,
00676            const throw_allocator_base<_Tp, _Cond>&)
00677     { return false; }
00678 
00679   /// Allocator throwing via limit condition.
00680   template<typename _Tp>
00681     struct throw_allocator_limit
00682     : public throw_allocator_base<_Tp, limit_condition>
00683     {
00684       template<typename _Tp1>
00685     struct rebind
00686     { typedef throw_allocator_limit<_Tp1> other; };
00687 
00688       throw_allocator_limit() throw() { }
00689 
00690       throw_allocator_limit(const throw_allocator_limit&) throw() { }
00691 
00692       template<typename _Tp1>
00693     throw_allocator_limit(const throw_allocator_limit<_Tp1>&) throw() { }
00694 
00695       ~throw_allocator_limit() throw() { }
00696     };
00697 
00698   /// Allocator throwing via random condition.
00699   template<typename _Tp>
00700     struct throw_allocator_random
00701     : public throw_allocator_base<_Tp, random_condition>
00702     {
00703       template<typename _Tp1>
00704     struct rebind
00705     { typedef throw_allocator_random<_Tp1> other; };
00706 
00707       throw_allocator_random() throw() { }
00708 
00709       throw_allocator_random(const throw_allocator_random&) throw() { }
00710 
00711       template<typename _Tp1>
00712     throw_allocator_random(const throw_allocator_random<_Tp1>&) throw() { }
00713 
00714       ~throw_allocator_random() throw() { }
00715     };
00716 
00717 _GLIBCXX_END_NAMESPACE
00718 
00719 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00720 
00721 # include <bits/functional_hash.h>
00722 
00723 namespace std
00724 {
00725   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
00726   template<>
00727     struct hash<__gnu_cxx::throw_value_limit>
00728     : public std::unary_function<__gnu_cxx::throw_value_limit, size_t>
00729     {
00730       size_t
00731       operator()(__gnu_cxx::throw_value_limit __val) const
00732       {
00733     std::hash<std::size_t> h;
00734     size_t __result = h(__val._M_i);
00735     return __result;
00736       }
00737     };
00738 
00739   /// Explicit specialization of std::hash for __gnu_cxx::throw_value_limit.
00740   template<>
00741     struct hash<__gnu_cxx::throw_value_random>
00742     : public std::unary_function<__gnu_cxx::throw_value_random, size_t>
00743     {
00744       size_t
00745       operator()(__gnu_cxx::throw_value_random __val) const
00746       {
00747     std::hash<std::size_t> h;
00748     size_t __result = h(__val._M_i);
00749     return __result;
00750       }
00751     };
00752 } // end namespace std
00753 #endif
00754 
00755 #endif

Generated on 9 Feb 2010 for libstdc++ by  doxygen 1.6.1