xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/ext/throw_allocator.h (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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