3 // Copyright (C) 2005, 2006, 2007 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 2, 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 // You should have received a copy of the GNU General Public License
17 // along with this library; see the file COPYING. If not, write to
18 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
19 // MA 02111-1307, USA.
21 // As a special exception, you may use this file as part of a free
22 // software library without restriction. Specifically, if other files
23 // instantiate templates or use macros or inline functions from this
24 // file, or you compile this file and link it with other files to
25 // produce an executable, this file does not by itself cause the
26 // resulting executable to be covered by the GNU General Public
27 // License. This exception does not however invalidate any other
28 // reasons why the executable file might be covered by the GNU General
31 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
33 // Permission to use, copy, modify, sell, and distribute this software
34 // is hereby granted without fee, provided that the above copyright
35 // notice appears in all copies, and that both that copyright notice
36 // and this permission notice appear in supporting documentation. None
37 // of the above authors, nor IBM Haifa Research Laboratories, make any
38 // representation about the suitability of this software for any
39 // purpose. It is provided "as is" without express or implied
42 /** @file ext/throw_allocator.h
43 * This file is a GNU extension to the Standard C++ Library.
45 * Contains an exception-throwing allocator, useful for testing
46 * exception safety. In addition, allocation addresses are stored and
50 #ifndef _THROW_ALLOCATOR_H
51 #define _THROW_ALLOCATOR_H 1
62 #include <bits/functexcept.h>
63 #include <bits/stl_move.h>
65 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx
)
67 class twister_rand_gen
70 twister_rand_gen(unsigned int seed
=
71 static_cast<unsigned int>(std::time(0)));
80 std::tr1::mt19937 _M_generator
;
83 /// Thown by throw_allocator.
84 struct forced_exception_error
: public std::exception
87 // Substitute for concurrence_error object in the case of -fno-exceptions.
89 __throw_forced_exception_error()
92 throw forced_exception_error();
99 class throw_allocator_base
103 init(unsigned long seed
);
106 set_throw_prob(double throw_prob
);
117 struct group_throw_prob_adjustor
119 group_throw_prob_adjustor(size_t size
)
120 : _M_throw_prob_orig(_S_throw_prob
)
123 1 - std::pow(double(1 - _S_throw_prob
), double(0.5 / (size
+ 1)));
126 ~group_throw_prob_adjustor()
127 { _S_throw_prob
= _M_throw_prob_orig
; }
130 const double _M_throw_prob_orig
;
133 struct zero_throw_prob_adjustor
135 zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob
)
136 { _S_throw_prob
= 0; }
138 ~zero_throw_prob_adjustor()
139 { _S_throw_prob
= _M_throw_prob_orig
; }
142 const double _M_throw_prob_orig
;
147 insert(void*, size_t);
150 erase(void*, size_t);
153 throw_conditionally();
155 // See if a particular address and size has been allocated by this
158 check_allocated(void*, size_t);
160 // See if a given label has been allocated by this allocator.
162 check_allocated(size_t);
165 typedef std::pair
<size_t, size_t> alloc_data_type
;
166 typedef std::map
<void*, alloc_data_type
> map_type
;
167 typedef map_type::value_type entry_type
;
168 typedef map_type::const_iterator const_iterator
;
169 typedef map_type::const_reference const_reference
;
172 operator<<(std::ostream
&, const throw_allocator_base
&);
175 make_entry(void*, size_t);
178 print_to_string(std::string
&);
181 print_to_string(std::string
&, const_reference
);
183 static twister_rand_gen _S_g
;
184 static map_type _S_map
;
185 static double _S_throw_prob
;
186 static size_t _S_label
;
189 /// Allocator class with logging and exception control.
191 class throw_allocator
: public throw_allocator_base
194 typedef size_t size_type
;
195 typedef ptrdiff_t difference_type
;
196 typedef T value_type
;
197 typedef value_type
* pointer
;
198 typedef const value_type
* const_pointer
;
199 typedef value_type
& reference
;
200 typedef const value_type
& const_reference
;
206 typedef throw_allocator
<U
> other
;
209 throw_allocator() throw() { }
211 throw_allocator(const throw_allocator
&) throw() { }
214 throw_allocator(const throw_allocator
<U
>&) throw() { }
216 ~throw_allocator() throw() { }
219 max_size() const throw()
220 { return std::allocator
<value_type
>().max_size(); }
223 allocate(size_type __n
, std::allocator
<void>::const_pointer hint
= 0)
225 if (__builtin_expect(__n
> this->max_size(), false))
226 std::__throw_bad_alloc();
228 throw_conditionally();
229 value_type
* const a
= std::allocator
<value_type
>().allocate(__n
, hint
);
230 insert(a
, sizeof(value_type
) * __n
);
235 construct(pointer __p
, const T
& val
)
236 { return std::allocator
<value_type
>().construct(__p
, val
); }
238 #ifdef __GXX_EXPERIMENTAL_CXX0X__
239 template<typename
... _Args
>
241 construct(pointer __p
, _Args
&&... __args
)
243 return std::allocator
<value_type
>().
244 construct(__p
, std::forward
<_Args
>(__args
)...);
250 { std::allocator
<value_type
>().destroy(__p
); }
253 deallocate(pointer __p
, size_type __n
)
255 erase(__p
, sizeof(value_type
) * __n
);
256 std::allocator
<value_type
>().deallocate(__p
, __n
);
260 check_allocated(pointer __p
, size_type __n
)
261 { throw_allocator_base::check_allocated(__p
, sizeof(value_type
) * __n
); }
264 check_allocated(size_type label
)
265 { throw_allocator_base::check_allocated(label
); }
270 operator==(const throw_allocator
<T
>&, const throw_allocator
<T
>&)
275 operator!=(const throw_allocator
<T
>&, const throw_allocator
<T
>&)
279 operator<<(std::ostream
& os
, const throw_allocator_base
& alloc
)
282 throw_allocator_base::print_to_string(error
);
287 // XXX Should be in .cc.
289 twister_rand_gen(unsigned int seed
) : _M_generator(seed
) { }
293 init(unsigned int seed
)
294 { _M_generator
.seed(seed
); }
300 const double eng_min
= _M_generator
.min();
301 const double eng_range
=
302 static_cast<const double>(_M_generator
.max() - eng_min
);
304 const double eng_res
=
305 static_cast<const double>(_M_generator() - eng_min
);
307 const double ret
= eng_res
/ eng_range
;
308 _GLIBCXX_DEBUG_ASSERT(ret
>= 0 && ret
<= 1);
312 twister_rand_gen
throw_allocator_base::_S_g
;
314 throw_allocator_base::map_type
315 throw_allocator_base::_S_map
;
317 double throw_allocator_base::_S_throw_prob
;
319 size_t throw_allocator_base::_S_label
= 0;
321 throw_allocator_base::entry_type
322 throw_allocator_base::make_entry(void* p
, size_t size
)
323 { return std::make_pair(p
, alloc_data_type(_S_label
, size
)); }
326 throw_allocator_base::init(unsigned long seed
)
330 throw_allocator_base::set_throw_prob(double throw_prob
)
331 { _S_throw_prob
= throw_prob
; }
334 throw_allocator_base::get_throw_prob()
335 { return _S_throw_prob
; }
338 throw_allocator_base::set_label(size_t l
)
342 throw_allocator_base::insert(void* p
, size_t size
)
344 const_iterator found_it
= _S_map
.find(p
);
345 if (found_it
!= _S_map
.end())
347 std::string
error("throw_allocator_base::insert");
348 error
+= "double insert!";
350 print_to_string(error
, make_entry(p
, size
));
351 print_to_string(error
, *found_it
);
352 std::__throw_logic_error(error
.c_str());
354 _S_map
.insert(make_entry(p
, size
));
358 throw_allocator_base::empty()
359 { return _S_map
.empty(); }
362 throw_allocator_base::erase(void* p
, size_t size
)
364 check_allocated(p
, size
);
369 throw_allocator_base::check_allocated(void* p
, size_t size
)
371 const_iterator found_it
= _S_map
.find(p
);
372 if (found_it
== _S_map
.end())
374 std::string
error("throw_allocator_base::check_allocated by value ");
375 error
+= "null erase!";
377 print_to_string(error
, make_entry(p
, size
));
378 std::__throw_logic_error(error
.c_str());
381 if (found_it
->second
.second
!= size
)
383 std::string
error("throw_allocator_base::check_allocated by value ");
384 error
+= "wrong-size erase!";
386 print_to_string(error
, make_entry(p
, size
));
387 print_to_string(error
, *found_it
);
388 std::__throw_logic_error(error
.c_str());
393 throw_allocator_base::check_allocated(size_t label
)
396 const_iterator it
= _S_map
.begin();
397 while (it
!= _S_map
.end())
399 if (it
->second
.first
== label
)
400 print_to_string(found
, *it
);
406 std::string
error("throw_allocator_base::check_allocated by label ");
409 std::__throw_logic_error(error
.c_str());
414 throw_allocator_base::throw_conditionally()
416 if (_S_g
.get_prob() < _S_throw_prob
)
417 __throw_forced_exception_error();
421 throw_allocator_base::print_to_string(std::string
& s
)
423 const_iterator begin
= throw_allocator_base::_S_map
.begin();
424 const_iterator end
= throw_allocator_base::_S_map
.end();
425 for (; begin
!= end
; ++begin
)
426 print_to_string(s
, *begin
);
430 throw_allocator_base::print_to_string(std::string
& s
, const_reference ref
)
433 const char tab('\t');
435 __builtin_sprintf(buf
, "%p", ref
.first
);
439 unsigned long l
= static_cast<unsigned long>(ref
.second
.first
);
440 __builtin_sprintf(buf
, "%lu", l
);
444 l
= static_cast<unsigned long>(ref
.second
.second
);
445 __builtin_sprintf(buf
, "%lu", l
);
450 _GLIBCXX_END_NAMESPACE