]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/include/ext/throw_allocator.h
gfc-internals.texi, [...]: Fix typos.
[thirdparty/gcc.git] / libstdc++-v3 / include / ext / throw_allocator.h
CommitLineData
a86151e1
BK
1// -*- C++ -*-
2
5b9daa7e 3// Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
a86151e1
BK
4//
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
748086b7 8// Foundation; either version 3, or (at your option) any later
a86151e1
BK
9// version.
10
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.
15
748086b7
JJ
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.
a86151e1 19
748086b7
JJ
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/>.
a86151e1
BK
24
25// Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
26
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
34// warranty.
35
65be6ddd 36/** @file ext/throw_allocator.h
78a53887
BK
37 * This file is a GNU extension to the Standard C++ Library.
38 *
39 * Contains an exception-throwing allocator, useful for testing
40 * exception safety. In addition, allocation addresses are stored and
41 * sanity checked.
42 */
43
a86151e1
BK
44#ifndef _THROW_ALLOCATOR_H
45#define _THROW_ALLOCATOR_H 1
46
47#include <cmath>
67a7356b 48#include <ctime>
a86151e1 49#include <map>
a86151e1
BK
50#include <string>
51#include <ostream>
52#include <stdexcept>
53#include <utility>
949d9ae1 54#include <bits/functexcept.h>
ca0f8fd1 55#include <bits/move.h>
5580c6e7
BK
56#ifdef __GXX_EXPERIMENTAL_CXX0X__
57# include <functional>
58# include <random>
59#else
60# include <tr1/functional>
61# include <tr1/random>
62#endif
a86151e1
BK
63
64_GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
65
5580c6e7 66 /**
5b9daa7e
BK
67 * @brief Thown by throw_allocator.
68 * @ingroup exceptions
69 */
a86151e1
BK
70 struct forced_exception_error : public std::exception
71 { };
72
949d9ae1
BK
73 // Substitute for concurrence_error object in the case of -fno-exceptions.
74 inline void
75 __throw_forced_exception_error()
76 {
77#if __EXCEPTIONS
78 throw forced_exception_error();
79#else
80 __builtin_abort();
81#endif
82 }
83
5580c6e7
BK
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.
88 struct annotate_base
a86151e1 89 {
5580c6e7
BK
90 annotate_base()
91 {
92 label();
93 map();
94 }
95
96 static void
97 set_label(size_t l)
98 { label() = l; }
99
100 static size_t
101 get_label()
102 { return label(); }
103
a86151e1 104 void
5580c6e7
BK
105 insert(void* p, size_t size)
106 {
107 if (p == NULL)
108 {
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());
112 }
a86151e1 113
5580c6e7
BK
114 const_iterator found = map().find(p);
115 if (found != map().end())
116 {
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());
121 }
a86151e1 122
5580c6e7
BK
123 map().insert(make_entry(p, size));
124 }
a86151e1 125
5580c6e7
BK
126 void
127 erase(void* p, size_t size)
128 {
129 check_allocated(p, size);
130 map().erase(p);
131 }
a86151e1 132
5580c6e7
BK
133 // See if a particular address and size has been allocated.
134 inline void
135 check_allocated(void* p, size_t size)
136 {
137 const_iterator found = map().find(p);
138 if (found == map().end())
139 {
140 std::string error("annotate_base::check_allocated by value "
141 "null erase!\n");
142 log_to_string(error, make_entry(p, size));
143 std::__throw_logic_error(error.c_str());
144 }
145
146 if (found->second.second != size)
147 {
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());
153 }
154 }
a86151e1 155
5580c6e7
BK
156 // See if a given label has been allocated.
157 inline void
158 check_allocated(size_t label)
a86151e1 159 {
5580c6e7
BK
160 const_iterator beg = map().begin();
161 const_iterator end = map().end();
162 std::string found;
163 while (beg != end)
164 {
165 if (beg->second.first == label)
166 log_to_string(found, *beg);
167 ++beg;
168 }
169
170 if (!found.empty())
171 {
172 std::string error("annotate_base::check_allocated by label\n");
173 error += found;
174 std::__throw_logic_error(error.c_str());
175 }
176 }
177
178 private:
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;
a86151e1 184
5580c6e7
BK
185 friend std::ostream&
186 operator<<(std::ostream&, const annotate_base&);
a86151e1 187
5580c6e7
BK
188 entry_type
189 make_entry(void* p, size_t size)
190 { return std::make_pair(p, data_type(get_label(), size)); }
191
192 void
193 log_to_string(std::string& s, const_reference ref) const
194 {
195 char buf[40];
196 const char tab('\t');
197 s += "label: ";
198 unsigned long l = static_cast<unsigned long>(ref.second.first);
199 __builtin_sprintf(buf, "%lu", l);
200 s += buf;
201 s += tab;
202 s += "size: ";
203 l = static_cast<unsigned long>(ref.second.second);
204 __builtin_sprintf(buf, "%lu", l);
205 s += buf;
206 s += tab;
207 s += "address: ";
208 __builtin_sprintf(buf, "%p", ref.first);
209 s += buf;
210 s += '\n';
211 }
212
213 static size_t&
214 label()
215 {
216 static size_t ll;
217 return ll;
218 }
219
220 static map_type&
221 map()
222 {
223 static map_type mp;
224 return mp;
225 }
226 };
227
228 inline std::ostream&
229 operator<<(std::ostream& os, const annotate_base& __b)
230 {
231 std::string error;
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);
237 return os << error;
238 }
239
240 /// Base class for probability control and throw.
241 struct probability_base
242 {
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
246 // block.
247 struct adjustor_base
248 {
a86151e1 249 private:
5580c6e7
BK
250 const double _M_prob;
251
252 public:
253 adjustor_base() : _M_prob(get_probability()) { }
254
255 virtual ~adjustor_base()
256 { set_probability(_M_prob); }
a86151e1
BK
257 };
258
5580c6e7
BK
259 // Group condition.
260 struct group_adjustor : public adjustor_base
a86151e1 261 {
5580c6e7
BK
262 group_adjustor(size_t size)
263 { set_probability(1 - std::pow(double(1 - get_probability()),
264 double(0.5 / (size + 1))));
265 }
266 };
a86151e1 267
5580c6e7
BK
268 // Never enter the condition.
269 struct never_adjustor : public adjustor_base
270 {
271 never_adjustor() { set_probability(0); }
272 };
a86151e1 273
5580c6e7
BK
274 // Always enter the condition.
275 struct always_adjustor : public adjustor_base
276 {
277 always_adjustor() { set_probability(1); }
a86151e1
BK
278 };
279
5580c6e7
BK
280 probability_base()
281 {
282 probability();
283 engine();
284 }
a86151e1
BK
285
286 static void
5580c6e7
BK
287 set_probability(double __p)
288 { probability() = __p; }
a86151e1 289
5580c6e7
BK
290 static double&
291 get_probability()
292 { return probability(); }
a86151e1 293
5580c6e7
BK
294 void
295 throw_conditionally()
296 {
297 if (generate() < get_probability())
298 __throw_forced_exception_error();
299 }
a86151e1 300
5580c6e7
BK
301 void
302 seed(unsigned long __s)
303 { engine().seed(__s); }
a86151e1
BK
304
305 private:
5580c6e7
BK
306#ifdef __GXX_EXPERIMENTAL_CXX0X__
307 typedef std::uniform_real_distribution<double> distribution_type;
308 typedef std::mt19937 engine_type;
309#else
310 typedef std::tr1::uniform_real<double> distribution_type;
311 typedef std::tr1::mt19937 engine_type;
312#endif
a86151e1 313
5580c6e7
BK
314 double
315 generate()
316 {
317#ifdef __GXX_EXPERIMENTAL_CXX0X__
318 const distribution_type distribution(0, 1);
319 static auto generator = std::bind(distribution, engine());
320#else
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);
325#endif
a86151e1 326
5580c6e7
BK
327 double random = generator();
328 if (random < distribution.min() || random > distribution.max())
329 {
330 std::string __s("throw_allocator::throw_conditionally");
331 __s += "\n";
332 __s += "random number generated is: ";
333 char buf[40];
334 __builtin_sprintf(buf, "%f", random);
335 __s += buf;
336 std::__throw_out_of_range(__s.c_str());
337 }
a86151e1 338
5580c6e7
BK
339 return random;
340 }
a86151e1 341
5580c6e7
BK
342 static double&
343 probability()
344 {
345 static double __p;
346 return __p;
347 }
a86151e1 348
5580c6e7
BK
349 static engine_type&
350 engine()
351 {
352 static engine_type __e;
353 return __e;
354 }
a86151e1
BK
355 };
356
5580c6e7 357 /**
5b9daa7e
BK
358 * @brief Allocator class with logging and exception control.
359 * @ingroup allocators
360 */
a86151e1 361 template<typename T>
5580c6e7
BK
362 class throw_allocator
363 : public probability_base, public annotate_base
a86151e1
BK
364 {
365 public:
3441f106
BK
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;
373
5580c6e7
BK
374 private:
375 std::allocator<value_type> _M_allocator;
a86151e1 376
5580c6e7 377 public:
a86151e1
BK
378 template<typename U>
379 struct rebind
380 {
5580c6e7 381 typedef throw_allocator<U> other;
a86151e1
BK
382 };
383
384 throw_allocator() throw() { }
385
3441f106 386 throw_allocator(const throw_allocator&) throw() { }
a86151e1 387
3441f106 388 template<typename U>
5580c6e7 389 throw_allocator(const throw_allocator<U>&) throw() { }
a86151e1
BK
390
391 ~throw_allocator() throw() { }
392
393 size_type
394 max_size() const throw()
5580c6e7 395 { return _M_allocator.max_size(); }
a86151e1
BK
396
397 pointer
b8637750 398 allocate(size_type __n, std::allocator<void>::const_pointer hint = 0)
a86151e1 399 {
e762c6f4 400 if (__n > this->max_size())
b8637750
BK
401 std::__throw_bad_alloc();
402
a86151e1 403 throw_conditionally();
5580c6e7 404 pointer const a = _M_allocator.allocate(__n, hint);
b8637750 405 insert(a, sizeof(value_type) * __n);
a86151e1
BK
406 return a;
407 }
408
409 void
b8637750 410 construct(pointer __p, const T& val)
5580c6e7 411 { return _M_allocator.construct(__p, val); }
a86151e1 412
61fcb9fb
PC
413#ifdef __GXX_EXPERIMENTAL_CXX0X__
414 template<typename... _Args>
5580c6e7
BK
415 void
416 construct(pointer __p, _Args&&... __args)
417 { return _M_allocator.construct(__p, std::forward<_Args>(__args)...); }
61fcb9fb
PC
418#endif
419
a86151e1 420 void
b8637750 421 destroy(pointer __p)
5580c6e7 422 { _M_allocator.destroy(__p); }
a86151e1
BK
423
424 void
b8637750 425 deallocate(pointer __p, size_type __n)
a86151e1 426 {
b8637750 427 erase(__p, sizeof(value_type) * __n);
5580c6e7 428 _M_allocator.deallocate(__p, __n);
a86151e1
BK
429 }
430
431 void
b8637750 432 check_allocated(pointer __p, size_type __n)
5580c6e7
BK
433 {
434 size_type __t = sizeof(value_type) * __n;
435 annotate_base::check_allocated(__p, __t);
436 }
3441f106 437
5580c6e7 438 using annotate_base::check_allocated;
a86151e1
BK
439 };
440
441 template<typename T>
442 inline bool
443 operator==(const throw_allocator<T>&, const throw_allocator<T>&)
444 { return true; }
445
446 template<typename T>
447 inline bool
448 operator!=(const throw_allocator<T>&, const throw_allocator<T>&)
449 { return false; }
450
a86151e1
BK
451_GLIBCXX_END_NAMESPACE
452
5580c6e7 453#endif