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 struct forced_exception_error
: public std::exception
86 // Substitute for concurrence_error object in the case of -fno-exceptions.
88 __throw_forced_exception_error()
91 throw forced_exception_error();
97 class throw_allocator_base
101 init(unsigned long seed
);
104 set_throw_prob(double throw_prob
);
115 struct group_throw_prob_adjustor
117 group_throw_prob_adjustor(size_t size
)
118 : _M_throw_prob_orig(_S_throw_prob
)
121 1 - std::pow(double(1 - _S_throw_prob
), double(0.5 / (size
+ 1)));
124 ~group_throw_prob_adjustor()
125 { _S_throw_prob
= _M_throw_prob_orig
; }
128 const double _M_throw_prob_orig
;
131 struct zero_throw_prob_adjustor
133 zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob
)
134 { _S_throw_prob
= 0; }
136 ~zero_throw_prob_adjustor()
137 { _S_throw_prob
= _M_throw_prob_orig
; }
140 const double _M_throw_prob_orig
;
145 insert(void*, size_t);
148 erase(void*, size_t);
151 throw_conditionally();
153 // See if a particular address and size has been allocated by this
156 check_allocated(void*, size_t);
158 // See if a given label has been allocated by this allocator.
160 check_allocated(size_t);
163 typedef std::pair
<size_t, size_t> alloc_data_type
;
164 typedef std::map
<void*, alloc_data_type
> map_type
;
165 typedef map_type::value_type entry_type
;
166 typedef map_type::const_iterator const_iterator
;
167 typedef map_type::const_reference const_reference
;
170 operator<<(std::ostream
&, const throw_allocator_base
&);
173 make_entry(void*, size_t);
176 print_to_string(std::string
&);
179 print_to_string(std::string
&, const_reference
);
181 static twister_rand_gen _S_g
;
182 static map_type _S_map
;
183 static double _S_throw_prob
;
184 static size_t _S_label
;
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 eng_min
= _M_generator
.min();
299 const double eng_range
=
300 static_cast<const double>(_M_generator
.max() - eng_min
);
302 const double eng_res
=
303 static_cast<const double>(_M_generator() - eng_min
);
305 const double ret
= eng_res
/ eng_range
;
306 _GLIBCXX_DEBUG_ASSERT(ret
>= 0 && ret
<= 1);
310 twister_rand_gen
throw_allocator_base::_S_g
;
312 throw_allocator_base::map_type
313 throw_allocator_base::_S_map
;
315 double throw_allocator_base::_S_throw_prob
;
317 size_t throw_allocator_base::_S_label
= 0;
319 throw_allocator_base::entry_type
320 throw_allocator_base::make_entry(void* p
, size_t size
)
321 { return std::make_pair(p
, alloc_data_type(_S_label
, size
)); }
324 throw_allocator_base::init(unsigned long seed
)
328 throw_allocator_base::set_throw_prob(double throw_prob
)
329 { _S_throw_prob
= throw_prob
; }
332 throw_allocator_base::get_throw_prob()
333 { return _S_throw_prob
; }
336 throw_allocator_base::set_label(size_t l
)
340 throw_allocator_base::insert(void* p
, size_t size
)
342 const_iterator found_it
= _S_map
.find(p
);
343 if (found_it
!= _S_map
.end())
345 std::string
error("throw_allocator_base::insert");
346 error
+= "double insert!";
348 print_to_string(error
, make_entry(p
, size
));
349 print_to_string(error
, *found_it
);
350 std::__throw_logic_error(error
.c_str());
352 _S_map
.insert(make_entry(p
, size
));
356 throw_allocator_base::empty()
357 { return _S_map
.empty(); }
360 throw_allocator_base::erase(void* p
, size_t size
)
362 check_allocated(p
, size
);
367 throw_allocator_base::check_allocated(void* p
, size_t size
)
369 const_iterator found_it
= _S_map
.find(p
);
370 if (found_it
== _S_map
.end())
372 std::string
error("throw_allocator_base::check_allocated by value ");
373 error
+= "null erase!";
375 print_to_string(error
, make_entry(p
, size
));
376 std::__throw_logic_error(error
.c_str());
379 if (found_it
->second
.second
!= size
)
381 std::string
error("throw_allocator_base::check_allocated by value ");
382 error
+= "wrong-size erase!";
384 print_to_string(error
, make_entry(p
, size
));
385 print_to_string(error
, *found_it
);
386 std::__throw_logic_error(error
.c_str());
391 throw_allocator_base::check_allocated(size_t label
)
394 const_iterator it
= _S_map
.begin();
395 while (it
!= _S_map
.end())
397 if (it
->second
.first
== label
)
398 print_to_string(found
, *it
);
404 std::string
error("throw_allocator_base::check_allocated by label ");
407 std::__throw_logic_error(error
.c_str());
412 throw_allocator_base::throw_conditionally()
414 if (_S_g
.get_prob() < _S_throw_prob
)
415 __throw_forced_exception_error();
419 throw_allocator_base::print_to_string(std::string
& s
)
421 const_iterator begin
= throw_allocator_base::_S_map
.begin();
422 const_iterator end
= throw_allocator_base::_S_map
.end();
423 for (; begin
!= end
; ++begin
)
424 print_to_string(s
, *begin
);
428 throw_allocator_base::print_to_string(std::string
& s
, const_reference ref
)
431 const char tab('\t');
433 __builtin_sprintf(buf
, "%p", ref
.first
);
437 unsigned long l
= static_cast<unsigned long>(ref
.second
.first
);
438 __builtin_sprintf(buf
, "%lu", l
);
442 l
= static_cast<unsigned long>(ref
.second
.second
);
443 __builtin_sprintf(buf
, "%lu", l
);
448 _GLIBCXX_END_NAMESPACE