3 // Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
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
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.
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.
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/>.
25 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
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
36 /** @file ext/throw_allocator.h
37 * This file is a GNU extension to the Standard C++ Library.
39 * Contains an exception-throwing allocator, useful for testing
40 * exception safety. In addition, allocation addresses are stored and
44 #ifndef _THROW_ALLOCATOR_H
45 #define _THROW_ALLOCATOR_H 1
54 #include <bits/functexcept.h>
55 #include <bits/move.h>
56 #ifdef __GXX_EXPERIMENTAL_CXX0X__
57 # include <functional>
60 # include <tr1/functional>
61 # include <tr1/random>
64 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
67 * @brief Thown by throw_allocator.
70 struct forced_exception_error : public std::exception
73 // Substitute for concurrence_error object in the case of -fno-exceptions.
75 __throw_forced_exception_error()
78 throw forced_exception_error();
84 // Base class for checking address and label information about
85 // allocations. Create a std::map between the allocated address
86 // (void*) and a datum for annotations, which are a pair of numbers
87 // corresponding to label and allocated size.
105 insert(void* p, size_t size)
109 std::string error("throw_allocator_base::insert null insert!\n");
110 log_to_string(error, make_entry(p, size));
111 std::__throw_logic_error(error.c_str());
114 const_iterator found = map().find(p);
115 if (found != map().end())
117 std::string error("throw_allocator_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());
123 map().insert(make_entry(p, size));
127 erase(void* p, size_t size)
129 check_allocated(p, size);
133 // See if a particular address and size has been allocated.
135 check_allocated(void* p, size_t size)
137 const_iterator found = map().find(p);
138 if (found == map().end())
140 std::string error("annotate_base::check_allocated by value "
142 log_to_string(error, make_entry(p, size));
143 std::__throw_logic_error(error.c_str());
146 if (found->second.second != size)
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());
156 // See if a given label has been allocated.
158 check_allocated(size_t label)
160 const_iterator beg = map().begin();
161 const_iterator end = map().end();
165 if (beg->second.first == label)
166 log_to_string(found, *beg);
172 std::string error("annotate_base::check_allocated by label\n");
174 std::__throw_logic_error(error.c_str());
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;
186 operator<<(std::ostream&, const annotate_base&);
189 make_entry(void* p, size_t size)
190 { return std::make_pair(p, data_type(get_label(), size)); }
193 log_to_string(std::string& s, const_reference ref) const
196 const char tab('\t');
198 unsigned long l = static_cast<unsigned long>(ref.second.first);
199 __builtin_sprintf(buf, "%lu", l);
203 l = static_cast<unsigned long>(ref.second.second);
204 __builtin_sprintf(buf, "%lu", l);
208 __builtin_sprintf(buf, "%p", ref.first);
229 operator<<(std::ostream& os, const annotate_base& __b)
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);
240 /// Base class for probability control and throw.
241 struct probability_base
243 // Scope-level probability adjustor objects: set probability for
244 // throw at the beginning of a scope block, and restores to
245 // previous probability when object is destroyed on exiting the
250 const double _M_prob;
253 adjustor_base() : _M_prob(get_probability()) { }
255 virtual ~adjustor_base()
256 { set_probability(_M_prob); }
260 struct group_adjustor : public adjustor_base
262 group_adjustor(size_t size)
263 { set_probability(1 - std::pow(double(1 - get_probability()),
264 double(0.5 / (size + 1))));
268 // Never enter the condition.
269 struct never_adjustor : public adjustor_base
271 never_adjustor() { set_probability(0); }
274 // Always enter the condition.
275 struct always_adjustor : public adjustor_base
277 always_adjustor() { set_probability(1); }
287 set_probability(double __p)
288 { probability() = __p; }
292 { return probability(); }
295 throw_conditionally()
297 if (generate() < get_probability())
298 __throw_forced_exception_error();
302 seed(unsigned long __s)
303 { engine().seed(__s); }
306 #ifdef __GXX_EXPERIMENTAL_CXX0X__
307 typedef std::uniform_real_distribution<double> distribution_type;
308 typedef std::mt19937 engine_type;
310 typedef std::tr1::uniform_real<double> distribution_type;
311 typedef std::tr1::mt19937 engine_type;
317 #ifdef __GXX_EXPERIMENTAL_CXX0X__
318 const distribution_type distribution(0, 1);
319 static auto generator = std::bind(distribution, engine());
321 // Use variate_generator to get normalized results.
322 typedef std::tr1::variate_generator<engine_type, distribution_type> gen_t;
323 distribution_type distribution(0, 1);
324 static gen_t generator(engine(), distribution);
327 double random = generator();
328 if (random < distribution.min() || random > distribution.max())
330 std::string __s("throw_allocator::throw_conditionally");
332 __s += "random number generated is: ";
334 __builtin_sprintf(buf, "%f", random);
336 std::__throw_out_of_range(__s.c_str());
352 static engine_type __e;
358 * @brief Allocator class with logging and exception control.
359 * @ingroup allocators
362 class throw_allocator
363 : public probability_base, public annotate_base
366 typedef size_t size_type;
367 typedef ptrdiff_t difference_type;
368 typedef T value_type;
369 typedef value_type* pointer;
370 typedef const value_type* const_pointer;
371 typedef value_type& reference;
372 typedef const value_type& const_reference;
375 std::allocator<value_type> _M_allocator;
381 typedef throw_allocator<U> other;
384 throw_allocator() throw() { }
386 throw_allocator(const throw_allocator&) throw() { }
389 throw_allocator(const throw_allocator<U>&) throw() { }
391 ~throw_allocator() throw() { }
394 max_size() const throw()
395 { return _M_allocator.max_size(); }
398 allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
400 if (__n > this->max_size())
401 std::__throw_bad_alloc();
403 throw_conditionally();
404 pointer const a = _M_allocator.allocate(__n, hint);
405 insert(a, sizeof(value_type) * __n);
410 construct(pointer __p, const T& val)
411 { return _M_allocator.construct(__p, val); }
413 #ifdef __GXX_EXPERIMENTAL_CXX0X__
414 template<typename... _Args>
416 construct(pointer __p, _Args&&... __args)
417 { return _M_allocator.construct(__p, std::forward<_Args>(__args)...); }
422 { _M_allocator.destroy(__p); }
425 deallocate(pointer __p, size_type __n)
427 erase(__p, sizeof(value_type) * __n);
428 _M_allocator.deallocate(__p, __n);
432 check_allocated(pointer __p, size_type __n)
434 size_type __t = sizeof(value_type) * __n;
435 annotate_base::check_allocated(__p, __t);
438 using annotate_base::check_allocated;
443 operator==(const throw_allocator<T>&, const throw_allocator<T>&)
448 operator!=(const throw_allocator<T>&, const throw_allocator<T>&)
451 _GLIBCXX_END_NAMESPACE