OSDN Git Service

2006-09-18 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / include / ext / throw_allocator.h
1 // -*- C++ -*-
2
3 // Copyright (C) 2005, 2006 Free Software Foundation, Inc.
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
8 // Foundation; either version 2, or (at your option) any later
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
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.
20
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
29 // Public License.
30
31 // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL.
32
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
40 // warranty.
41
42 /**
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.
46  */
47
48 #ifndef _THROW_ALLOCATOR_H
49 #define _THROW_ALLOCATOR_H 1
50
51 #include <cmath>
52 #include <map>
53 #include <set>
54 #include <string>
55 #include <ostream>
56 #include <stdexcept>
57 #include <utility>
58 #include <tr1/random>
59
60 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
61
62   class twister_rand_gen
63   {
64   public:
65     twister_rand_gen(unsigned int seed = 
66                      static_cast<unsigned int>(std::time(0)));
67     
68     void
69     init(unsigned int);
70     
71     double
72     get_prob();
73     
74   private:
75     std::tr1::mt19937 _M_generator;
76   };
77
78
79   struct forced_exception_error : public std::exception
80   { };
81
82   class throw_allocator_base
83   {
84   public:
85     void
86     init(unsigned long seed);
87
88     static void
89     set_throw_prob(double throw_prob);
90
91     static double
92     get_throw_prob();
93
94     static void
95     set_label(size_t l);
96
97     static bool
98     empty();
99
100     struct group_throw_prob_adjustor
101     {
102       group_throw_prob_adjustor(size_t size) 
103       : _M_throw_prob_orig(_S_throw_prob)
104       {
105         _S_throw_prob =
106           1 - ::pow(double(1 - _S_throw_prob), double(0.5 / (size + 1)));
107       }
108
109       ~group_throw_prob_adjustor()
110       { _S_throw_prob = _M_throw_prob_orig; }
111
112     private:
113       const double _M_throw_prob_orig;
114     };
115
116     struct zero_throw_prob_adjustor
117     {
118       zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob)
119       { _S_throw_prob = 0; }
120
121       ~zero_throw_prob_adjustor()
122       { _S_throw_prob = _M_throw_prob_orig; }
123
124     private:
125       const double _M_throw_prob_orig;
126     };
127
128   protected:
129     static void
130     insert(void*, size_t);
131
132     static void
133     erase(void*, size_t);
134
135     static void
136     throw_conditionally();
137
138     static void
139     assert_allocatod(const void*, size_t);
140
141     static void
142     check_allocated(void*, size_t);
143
144   private:
145     typedef std::pair<size_t, size_t>           alloc_data_type;
146     typedef std::map<void*, alloc_data_type>    map_type;
147     typedef map_type::value_type                entry_type;
148     typedef map_type::const_iterator            const_iterator;
149     typedef map_type::const_reference           const_reference;
150
151     friend std::ostream& 
152     operator<<(std::ostream&, const throw_allocator_base&);
153
154     static entry_type
155     make_entry(void*, size_t);
156
157     static void
158     print_to_string(std::string&);
159
160     static void
161     print_to_string(std::string&, const_reference);
162
163     static twister_rand_gen     _S_g;
164     static map_type             _S_map;
165     static double               _S_throw_prob;
166     static size_t               _S_label;
167   };
168
169
170   template<typename T>
171     class throw_allocator : public throw_allocator_base
172     {
173     public:
174       typedef size_t            size_type;
175       typedef ptrdiff_t         difference_type;
176       typedef T*                pointer;
177       typedef const T*          const_pointer;
178       typedef T&                reference;
179       typedef const T&          const_reference;
180       typedef T                 value_type;
181
182       template<typename U>
183       struct rebind
184       {
185         typedef throw_allocator<U> other;
186       };
187
188       throw_allocator() throw() { }
189
190       throw_allocator(const throw_allocator<T>&) throw() { }
191
192       template <class U>
193       throw_allocator(const throw_allocator<U>&) throw() { }
194
195       ~throw_allocator() throw() { }
196
197       size_type
198       max_size() const throw()
199       { return std::allocator<T>().max_size(); }
200
201       pointer
202       allocate(size_type num, std::allocator<void>::const_pointer hint = 0)
203       {
204         throw_conditionally();
205         T* const a = std::allocator<T>().allocate(num, hint);
206         insert(a, sizeof(T) * num);
207         return a;
208       }
209
210       void
211       construct(pointer p, const T& val)
212       { return std::allocator<T>().construct(p, val); }
213
214       void
215       destroy(pointer p)
216       { std::allocator<T>().destroy(p); }
217
218       void
219       deallocate(pointer p, size_type num)
220       {
221         erase(p, sizeof(T) * num);
222         std::allocator<T>().deallocate(p, num);
223       }
224
225       void
226       check_allocated(pointer p, size_type num)
227       { throw_allocator_base::check_allocated(p, sizeof(T) * num); }
228     };
229
230   template<typename T>
231     inline bool
232     operator==(const throw_allocator<T>&, const throw_allocator<T>&)
233     { return true; }
234
235   template<typename T>
236     inline bool
237     operator!=(const throw_allocator<T>&, const throw_allocator<T>&)
238     { return false; }
239
240   std::ostream& 
241   operator<<(std::ostream& os, const throw_allocator_base& alloc)
242   {
243     std::string error;
244     throw_allocator_base::print_to_string(error);
245     os << error;
246     return os;
247   }
248
249   // XXX Should be in .cc.
250   twister_rand_gen::
251   twister_rand_gen(unsigned int seed) : _M_generator(seed)  { }
252
253   void
254   twister_rand_gen::
255   init(unsigned int seed)
256   { _M_generator.seed(seed); }
257
258   double
259   twister_rand_gen::
260   get_prob()
261   {
262     const double eng_min = _M_generator.min();
263     const double eng_range =
264       static_cast<const double>(_M_generator.max() - eng_min);
265
266     const double eng_res =
267       static_cast<const double>(_M_generator() - eng_min);
268
269     const double ret = eng_res / eng_range;
270     _GLIBCXX_DEBUG_ASSERT(ret >= 0 && ret <= 1);
271     return ret;
272   }
273
274   twister_rand_gen throw_allocator_base::_S_g;
275
276   throw_allocator_base::map_type
277   throw_allocator_base::_S_map;
278
279   double throw_allocator_base::_S_throw_prob;
280
281   size_t throw_allocator_base::_S_label = 0;
282
283   throw_allocator_base::entry_type
284   throw_allocator_base::make_entry(void* p, size_t size)
285   { return std::make_pair(p, alloc_data_type(_S_label, size)); }
286
287   void
288   throw_allocator_base::init(unsigned long seed)
289   { _S_g.init(seed); }
290
291   void
292   throw_allocator_base::set_throw_prob(double throw_prob)
293   { _S_throw_prob = throw_prob; }
294
295   double
296   throw_allocator_base::get_throw_prob()
297   { return _S_throw_prob; }
298
299   void
300   throw_allocator_base::set_label(size_t l)
301   { _S_label = l; }
302
303   void
304   throw_allocator_base::insert(void* p, size_t size)
305   {
306     const_iterator found_it = _S_map.find(p);
307     if (found_it != _S_map.end())
308       {
309         std::string error("throw_allocator_base::insert");
310         error += "double insert!";
311         error += '\n';
312         print_to_string(error, make_entry(p, size));
313         print_to_string(error, *found_it);
314         throw std::logic_error(error);
315       }
316     _S_map.insert(make_entry(p, size));
317   }
318
319   bool
320   throw_allocator_base::empty()
321   { return _S_map.empty(); }
322
323   void
324   throw_allocator_base::erase(void* p, size_t size)
325   {
326     check_allocated(p, size);
327     _S_map.erase(p);
328   }
329
330   void
331   throw_allocator_base::check_allocated(void* p, size_t size)
332   {
333     const_iterator found_it = _S_map.find(p);
334     if (found_it == _S_map.end())
335       {
336         std::string error("throw_allocator_base::check_allocated");
337         error += "null erase!";
338         error += '\n';
339         print_to_string(error, make_entry(p, size));
340         throw std::logic_error(error);
341       }
342
343     if (found_it->second.second != size)
344       {
345         std::string error("throw_allocator_base::check_allocated");
346         error += "wrong-size erase!";
347         error += '\n';
348         print_to_string(error, make_entry(p, size));
349         print_to_string(error, *found_it);
350         throw std::logic_error(error);
351       }
352   }
353
354   void
355   throw_allocator_base::throw_conditionally()
356   {
357     if (_S_g.get_prob() < _S_throw_prob)
358       throw forced_exception_error();
359   }
360
361   void
362   throw_allocator_base::print_to_string(std::string& s)
363   {
364     const_iterator it = throw_allocator_base::_S_map.begin();
365     const_iterator end_it = throw_allocator_base::_S_map.end();
366     for (; it != end_it; ++it)
367       print_to_string(s, *it);
368     s += '\n';
369   }
370
371   void
372   throw_allocator_base::print_to_string(std::string& s, const_reference ref)
373   {
374     s += reinterpret_cast<const unsigned long>(ref.first);
375     s += ": ";
376     s += ref.second.first ;
377     s += ", ";
378     s += ref.second.second;
379     s += '\n';
380   }
381
382 _GLIBCXX_END_NAMESPACE
383
384 #endif