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
56 #include <bits/functexcept.h>
57 #include <bits/move.h>
59 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx
)
61 class twister_rand_gen
64 std::tr1::mt19937 _M_generator
;
67 twister_rand_gen(unsigned int s
= static_cast<unsigned int>(std::time(0)));
77 * @brief Thown by throw_allocator.
80 struct forced_exception_error
: public std::exception
83 // Substitute for concurrence_error object in the case of -fno-exceptions.
85 __throw_forced_exception_error()
88 throw forced_exception_error();
95 class throw_allocator_base
99 init(unsigned long seed
);
102 set_throw_prob(double throw_prob
);
113 struct group_throw_prob_adjustor
115 group_throw_prob_adjustor(size_t size
) : _M_throw_prob_orig(_S_throw_prob
)
118 1 - std::pow(double(1 - _S_throw_prob
), double(0.5 / (size
+ 1)));
121 ~group_throw_prob_adjustor()
122 { _S_throw_prob
= _M_throw_prob_orig
; }
125 const double _M_throw_prob_orig
;
128 struct zero_throw_prob_adjustor
130 zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob
)
131 { _S_throw_prob
= 0; }
133 ~zero_throw_prob_adjustor()
134 { _S_throw_prob
= _M_throw_prob_orig
; }
137 const double _M_throw_prob_orig
;
142 insert(void*, size_t);
145 erase(void*, size_t);
148 throw_conditionally();
150 // See if a particular address and size has been allocated by this
153 check_allocated(void*, size_t);
155 // See if a given label has been allocated by this allocator.
157 check_allocated(size_t);
160 typedef std::pair
<size_t, size_t> alloc_data_type
;
161 typedef std::map
<void*, alloc_data_type
> map_type
;
162 typedef map_type::value_type entry_type
;
163 typedef map_type::const_iterator const_iterator
;
164 typedef map_type::const_reference const_reference
;
167 operator<<(std::ostream
&, const throw_allocator_base
&);
170 make_entry(void*, size_t);
173 print_to_string(std::string
&);
176 print_to_string(std::string
&, const_reference
);
178 static twister_rand_gen _S_g
;
179 static map_type _S_map
;
180 static double _S_throw_prob
;
181 static size_t _S_label
;
185 * @brief Allocator class with logging and exception control.
186 * @ingroup allocators
189 class throw_allocator
: public throw_allocator_base
192 typedef size_t size_type
;
193 typedef ptrdiff_t difference_type
;
194 typedef T value_type
;
195 typedef value_type
* pointer
;
196 typedef const value_type
* const_pointer
;
197 typedef value_type
& reference
;
198 typedef const value_type
& const_reference
;
204 typedef throw_allocator
<U
> other
;
207 throw_allocator() throw() { }
209 throw_allocator(const throw_allocator
&) throw() { }
212 throw_allocator(const throw_allocator
<U
>&) throw() { }
214 ~throw_allocator() throw() { }
217 max_size() const throw()
218 { return std::allocator
<value_type
>().max_size(); }
221 allocate(size_type __n
, std::allocator
<void>::const_pointer hint
= 0)
223 if (__builtin_expect(__n
> this->max_size(), false))
224 std::__throw_bad_alloc();
226 throw_conditionally();
227 value_type
* const a
= std::allocator
<value_type
>().allocate(__n
, hint
);
228 insert(a
, sizeof(value_type
) * __n
);
233 construct(pointer __p
, const T
& val
)
234 { return std::allocator
<value_type
>().construct(__p
, val
); }
236 #ifdef __GXX_EXPERIMENTAL_CXX0X__
237 template<typename
... _Args
>
239 construct(pointer __p
, _Args
&&... __args
)
241 return std::allocator
<value_type
>().
242 construct(__p
, std::forward
<_Args
>(__args
)...);
248 { std::allocator
<value_type
>().destroy(__p
); }
251 deallocate(pointer __p
, size_type __n
)
253 erase(__p
, sizeof(value_type
) * __n
);
254 std::allocator
<value_type
>().deallocate(__p
, __n
);
258 check_allocated(pointer __p
, size_type __n
)
259 { throw_allocator_base::check_allocated(__p
, sizeof(value_type
) * __n
); }
262 check_allocated(size_type label
)
263 { throw_allocator_base::check_allocated(label
); }
268 operator==(const throw_allocator
<T
>&, const throw_allocator
<T
>&)
273 operator!=(const throw_allocator
<T
>&, const throw_allocator
<T
>&)
277 operator<<(std::ostream
& os
, const throw_allocator_base
& alloc
)
280 throw_allocator_base::print_to_string(error
);
285 // XXX Should be in .cc.
287 twister_rand_gen(unsigned int seed
) : _M_generator(seed
) { }
291 init(unsigned int seed
)
292 { _M_generator
.seed(seed
); }
298 const double min
= _M_generator
.min();
299 const double res
= static_cast<const double>(_M_generator() - min
);
300 const double range
= static_cast<const double>(_M_generator
.max() - min
);
301 const double ret
= res
/ range
;
302 _GLIBCXX_DEBUG_ASSERT(ret
>= 0 && ret
<= 1);
306 twister_rand_gen
throw_allocator_base::_S_g
;
308 throw_allocator_base::map_type
309 throw_allocator_base::_S_map
;
311 double throw_allocator_base::_S_throw_prob
;
313 size_t throw_allocator_base::_S_label
= 0;
315 throw_allocator_base::entry_type
316 throw_allocator_base::make_entry(void* p
, size_t size
)
317 { return std::make_pair(p
, alloc_data_type(_S_label
, size
)); }
320 throw_allocator_base::init(unsigned long seed
)
324 throw_allocator_base::set_throw_prob(double throw_prob
)
325 { _S_throw_prob
= throw_prob
; }
328 throw_allocator_base::get_throw_prob()
329 { return _S_throw_prob
; }
332 throw_allocator_base::set_label(size_t l
)
336 throw_allocator_base::insert(void* p
, size_t size
)
338 const_iterator found_it
= _S_map
.find(p
);
339 if (found_it
!= _S_map
.end())
341 std::string
error("throw_allocator_base::insert");
342 error
+= "double insert!";
344 print_to_string(error
, make_entry(p
, size
));
345 print_to_string(error
, *found_it
);
346 std::__throw_logic_error(error
.c_str());
348 _S_map
.insert(make_entry(p
, size
));
352 throw_allocator_base::empty()
353 { return _S_map
.empty(); }
356 throw_allocator_base::erase(void* p
, size_t size
)
358 check_allocated(p
, size
);
363 throw_allocator_base::check_allocated(void* p
, size_t size
)
365 const_iterator found_it
= _S_map
.find(p
);
366 if (found_it
== _S_map
.end())
368 std::string
error("throw_allocator_base::check_allocated by value ");
369 error
+= "null erase!";
371 print_to_string(error
, make_entry(p
, size
));
372 std::__throw_logic_error(error
.c_str());
375 if (found_it
->second
.second
!= size
)
377 std::string
error("throw_allocator_base::check_allocated by value ");
378 error
+= "wrong-size erase!";
380 print_to_string(error
, make_entry(p
, size
));
381 print_to_string(error
, *found_it
);
382 std::__throw_logic_error(error
.c_str());
387 throw_allocator_base::check_allocated(size_t label
)
390 const_iterator it
= _S_map
.begin();
391 while (it
!= _S_map
.end())
393 if (it
->second
.first
== label
)
395 print_to_string(found
, *it
);
402 std::string
error("throw_allocator_base::check_allocated by label ");
405 std::__throw_logic_error(error
.c_str());
410 throw_allocator_base::throw_conditionally()
412 if (_S_g
.get_prob() < _S_throw_prob
)
413 __throw_forced_exception_error();
417 throw_allocator_base::print_to_string(std::string
& s
)
419 const_iterator begin
= throw_allocator_base::_S_map
.begin();
420 const_iterator end
= throw_allocator_base::_S_map
.end();
421 for (; begin
!= end
; ++begin
)
422 print_to_string(s
, *begin
);
426 throw_allocator_base::print_to_string(std::string
& s
, const_reference ref
)
429 const char tab('\t');
431 __builtin_sprintf(buf
, "%p", ref
.first
);
435 unsigned long l
= static_cast<unsigned long>(ref
.second
.first
);
436 __builtin_sprintf(buf
, "%lu", l
);
440 l
= static_cast<unsigned long>(ref
.second
.second
);
441 __builtin_sprintf(buf
, "%lu", l
);
446 _GLIBCXX_END_NAMESPACE