3 // Copyright (C) 2005, 2006 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
43 * @file throw_allocator.h Contains an exception-throwing allocator
44 * useful for testing exception safety. In addition, allocation
45 * addresses are stored and sanity checked.
48 #ifndef _THROW_ALLOCATOR_H
49 #define _THROW_ALLOCATOR_H 1
60 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
62 class twister_rand_gen
65 twister_rand_gen(unsigned int seed =
66 static_cast<unsigned int>(std::time(0)));
75 std::tr1::mt19937 _M_generator;
79 struct forced_exception_error : public std::exception
82 class throw_allocator_base
86 init(unsigned long seed);
89 set_throw_prob(double throw_prob);
100 struct group_throw_prob_adjustor
102 group_throw_prob_adjustor(size_t size)
103 : _M_throw_prob_orig(_S_throw_prob)
106 1 - ::pow(double(1 - _S_throw_prob), double(0.5 / (size + 1)));
109 ~group_throw_prob_adjustor()
110 { _S_throw_prob = _M_throw_prob_orig; }
113 const double _M_throw_prob_orig;
116 struct zero_throw_prob_adjustor
118 zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob)
119 { _S_throw_prob = 0; }
121 ~zero_throw_prob_adjustor()
122 { _S_throw_prob = _M_throw_prob_orig; }
125 const double _M_throw_prob_orig;
130 insert(void*, size_t);
133 erase(void*, size_t);
136 throw_conditionally();
138 // See if a particular address and size has been allocated by this
141 check_allocated(void*, size_t);
143 // See if a given label has been allocated by this allocator.
145 check_allocated(size_t);
148 typedef std::pair<size_t, size_t> alloc_data_type;
149 typedef std::map<void*, alloc_data_type> map_type;
150 typedef map_type::value_type entry_type;
151 typedef map_type::const_iterator const_iterator;
152 typedef map_type::const_reference const_reference;
155 operator<<(std::ostream&, const throw_allocator_base&);
158 make_entry(void*, size_t);
161 print_to_string(std::string&);
164 print_to_string(std::string&, const_reference);
166 static twister_rand_gen _S_g;
167 static map_type _S_map;
168 static double _S_throw_prob;
169 static size_t _S_label;
174 class throw_allocator : public throw_allocator_base
177 typedef size_t size_type;
178 typedef ptrdiff_t difference_type;
179 typedef T value_type;
180 typedef value_type* pointer;
181 typedef const value_type* const_pointer;
182 typedef value_type& reference;
183 typedef const value_type& const_reference;
189 typedef throw_allocator<U> other;
192 throw_allocator() throw() { }
194 throw_allocator(const throw_allocator&) throw() { }
197 throw_allocator(const throw_allocator<U>&) throw() { }
199 ~throw_allocator() throw() { }
202 max_size() const throw()
203 { return std::allocator<value_type>().max_size(); }
206 allocate(size_type num, std::allocator<void>::const_pointer hint = 0)
208 throw_conditionally();
209 value_type* const a = std::allocator<value_type>().allocate(num, hint);
210 insert(a, sizeof(value_type) * num);
215 construct(pointer p, const T& val)
216 { return std::allocator<value_type>().construct(p, val); }
220 { std::allocator<value_type>().destroy(p); }
223 deallocate(pointer p, size_type num)
225 erase(p, sizeof(value_type) * num);
226 std::allocator<value_type>().deallocate(p, num);
230 check_allocated(pointer p, size_type num)
231 { throw_allocator_base::check_allocated(p, sizeof(value_type) * num); }
234 check_allocated(size_type label)
235 { throw_allocator_base::check_allocated(label); }
240 operator==(const throw_allocator<T>&, const throw_allocator<T>&)
245 operator!=(const throw_allocator<T>&, const throw_allocator<T>&)
249 operator<<(std::ostream& os, const throw_allocator_base& alloc)
252 throw_allocator_base::print_to_string(error);
257 // XXX Should be in .cc.
259 twister_rand_gen(unsigned int seed) : _M_generator(seed) { }
263 init(unsigned int seed)
264 { _M_generator.seed(seed); }
270 const double eng_min = _M_generator.min();
271 const double eng_range =
272 static_cast<const double>(_M_generator.max() - eng_min);
274 const double eng_res =
275 static_cast<const double>(_M_generator() - eng_min);
277 const double ret = eng_res / eng_range;
278 _GLIBCXX_DEBUG_ASSERT(ret >= 0 && ret <= 1);
282 twister_rand_gen throw_allocator_base::_S_g;
284 throw_allocator_base::map_type
285 throw_allocator_base::_S_map;
287 double throw_allocator_base::_S_throw_prob;
289 size_t throw_allocator_base::_S_label = 0;
291 throw_allocator_base::entry_type
292 throw_allocator_base::make_entry(void* p, size_t size)
293 { return std::make_pair(p, alloc_data_type(_S_label, size)); }
296 throw_allocator_base::init(unsigned long seed)
300 throw_allocator_base::set_throw_prob(double throw_prob)
301 { _S_throw_prob = throw_prob; }
304 throw_allocator_base::get_throw_prob()
305 { return _S_throw_prob; }
308 throw_allocator_base::set_label(size_t l)
312 throw_allocator_base::insert(void* p, size_t size)
314 const_iterator found_it = _S_map.find(p);
315 if (found_it != _S_map.end())
317 std::string error("throw_allocator_base::insert");
318 error += "double insert!";
320 print_to_string(error, make_entry(p, size));
321 print_to_string(error, *found_it);
322 throw std::logic_error(error);
324 _S_map.insert(make_entry(p, size));
328 throw_allocator_base::empty()
329 { return _S_map.empty(); }
332 throw_allocator_base::erase(void* p, size_t size)
334 check_allocated(p, size);
339 throw_allocator_base::check_allocated(void* p, size_t size)
341 const_iterator found_it = _S_map.find(p);
342 if (found_it == _S_map.end())
344 std::string error("throw_allocator_base::check_allocated by value ");
345 error += "null erase!";
347 print_to_string(error, make_entry(p, size));
348 throw std::logic_error(error);
351 if (found_it->second.second != size)
353 std::string error("throw_allocator_base::check_allocated by value ");
354 error += "wrong-size erase!";
356 print_to_string(error, make_entry(p, size));
357 print_to_string(error, *found_it);
358 throw std::logic_error(error);
363 throw_allocator_base::check_allocated(size_t label)
366 const_iterator it = _S_map.begin();
367 while (it != _S_map.end())
369 if (it->second.first == label)
370 print_to_string(found, *it);
376 std::string error("throw_allocator_base::check_allocated by label ");
379 throw std::logic_error(error);
384 throw_allocator_base::throw_conditionally()
386 if (_S_g.get_prob() < _S_throw_prob)
387 throw forced_exception_error();
391 throw_allocator_base::print_to_string(std::string& s)
393 const_iterator begin = throw_allocator_base::_S_map.begin();
394 const_iterator end = throw_allocator_base::_S_map.end();
395 for (; begin != end; ++begin)
396 print_to_string(s, *begin);
400 throw_allocator_base::print_to_string(std::string& s, const_reference ref)
403 const char tab('\t');
405 sprintf(buf, "%p", ref.first);
409 sprintf(buf, "%u", ref.second.first);
413 sprintf(buf, "%u", ref.second.second);
418 _GLIBCXX_END_NAMESPACE