OSDN Git Service

2006-01-04 Paolo Carlini <pcarlini@suse.de>
[pf3gnuchains/gcc-fork.git] / libstdc++-v3 / testsuite / testsuite_allocator.h
1 // -*- C++ -*-
2 // Testing allocator for the C++ library testsuite.
3 //
4 // Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 2, or (at your option)
10 // any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING.  If not, write to the Free
19 // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 // USA.
21 //
22 // As a special exception, you may use this file as part of a free software
23 // library without restriction.  Specifically, if other files instantiate
24 // templates or use macros or inline functions from this file, or you compile
25 // this file and link it with other files to produce an executable, this
26 // file does not by itself cause the resulting executable to be covered by
27 // the GNU General Public License.  This exception does not however
28 // invalidate any other reasons why the executable file might be covered by
29 // the GNU General Public License.
30
31 // This file provides an test instrumentation allocator that can be
32 // used to verify allocation functionality of standard library
33 // containers.  2002.11.25 smw
34
35 #ifndef _GLIBCXX_TESTSUITE_ALLOCATOR_H
36 #define _GLIBCXX_TESTSUITE_ALLOCATOR_H
37
38 #include <cstddef>
39 #include <limits>
40 #include <tr1/unordered_map>
41 #include <cassert>
42
43 namespace 
44 {
45   bool new_called = false;
46   bool delete_called = false;
47 };
48
49 namespace __gnu_test
50 {
51   class allocation_tracker
52   {
53   public:
54     typedef std::size_t    size_type; 
55     
56     static void*
57     allocate(size_type blocksize)
58     {
59       allocationTotal_ += blocksize;
60       return ::operator new(blocksize);
61     }
62     
63     static void
64     construct() { constructCount_++; }
65
66     static void
67     destroy() { destructCount_++; }
68
69     static void
70     deallocate(void* p, size_type blocksize)
71     {
72       ::operator delete(p);
73       deallocationTotal_ += blocksize;
74     }
75     
76     static size_type
77     allocationTotal() { return allocationTotal_; }
78     
79     static size_type
80     deallocationTotal() { return deallocationTotal_; }
81     
82     static int
83     constructCount() { return constructCount_; }
84
85     static int
86     destructCount() { return destructCount_; }
87     
88     static void
89     resetCounts()
90     {
91       allocationTotal_ = 0;
92       deallocationTotal_ = 0;
93       constructCount_ = 0;
94     destructCount_ = 0;
95     }
96
97  private:
98     static size_type  allocationTotal_;
99     static size_type  deallocationTotal_;
100     static int        constructCount_;
101     static int        destructCount_;
102   };
103
104   // A simple basic allocator that just forwards to the
105   // allocation_tracker to fulfill memory requests.  This class is
106   // templated on the target object type, but tracker isn't.
107   template<class T>
108   class tracker_alloc
109   {
110   public:
111     typedef T              value_type;
112     typedef T*             pointer;
113     typedef const T*       const_pointer;
114     typedef T&             reference;
115     typedef const T&       const_reference;
116     typedef std::size_t    size_type; 
117     typedef std::ptrdiff_t difference_type; 
118     
119     template<class U> struct rebind { typedef tracker_alloc<U> other; };
120     
121     pointer
122     address(reference value) const
123     { return &value; }
124     
125     const_pointer
126     address(const_reference value) const
127     { return &value; }
128     
129     tracker_alloc() throw()
130     { }
131
132     tracker_alloc(const tracker_alloc&) throw()
133     { }
134
135     template<class U>
136       tracker_alloc(const tracker_alloc<U>&) throw()
137       { }
138
139     ~tracker_alloc() throw()
140     { }
141
142     size_type
143     max_size() const throw()
144     { return std::numeric_limits<std::size_t>::max() / sizeof(T); }
145
146     pointer
147     allocate(size_type n, const void* = 0)
148     { 
149       return static_cast<pointer>(allocation_tracker::allocate(n * sizeof(T)));
150     }
151
152     void
153     construct(pointer p, const T& value)
154     {
155       new (p) T(value);
156       allocation_tracker::construct();
157     }
158
159     void
160     destroy(pointer p)
161     {
162       p->~T();
163       allocation_tracker::destroy();
164     }
165
166     void
167     deallocate(pointer p, size_type num)
168     { allocation_tracker::deallocate(p, num * sizeof(T)); }
169   };
170
171   template<class T1, class T2>
172     bool
173     operator==(const tracker_alloc<T1>&, const tracker_alloc<T2>&) throw()
174     { return true; }
175
176   template<class T1, class T2>
177     bool
178     operator!=(const tracker_alloc<T1>&, const tracker_alloc<T2>&) throw()
179     { return false; }
180
181   bool
182   check_construct_destroy(const char* tag, int expected_c, int expected_d);
183
184   template<typename Alloc, bool uses_global_new>
185     bool 
186     check_new(Alloc a = Alloc())
187     {
188       bool test __attribute__((unused)) = true;
189       a.allocate(10);
190       test &= ( new_called == uses_global_new );
191       return test;
192     }
193
194   template<typename Alloc, bool uses_global_delete>
195     bool 
196     check_delete(Alloc a = Alloc())
197     {
198       bool test __attribute__((unused)) = true;
199       typename Alloc::pointer p = a.allocate(10);
200       a.deallocate(p, 10);
201       test &= ( delete_called == uses_global_delete );
202       return test;
203     }
204
205   template<typename Alloc>
206     bool
207     check_deallocate_null()
208     {
209       // Let's not core here...
210       Alloc  a;
211       a.deallocate(NULL, 1);
212       a.deallocate(NULL, 10);
213       return true;
214     }
215
216   template<typename Alloc>
217     bool 
218     check_allocate_max_size()
219     {
220       Alloc a;
221       try
222         {
223           a.allocate(a.max_size() + 1);
224         }
225       catch(std::bad_alloc&)
226         {
227           return true;
228         }
229       catch(...)
230         {
231           throw;
232         }
233       throw;
234     }
235
236
237   // A simple allocator which can be constructed endowed of a given
238   // "personality" (an integer), queried in operator== to simulate the
239   // behavior of realworld "unequal" allocators (i.e., not exploiting
240   // the provision in 20.1.5/4, first bullet).  A global unordered_map,
241   // filled at allocation time with (pointer, personality) pairs, is
242   // then consulted to enforce the requirements in Table 32 about
243   // deallocation vs allocator equality.  Note that this allocator is
244   // swappable, not assignable, consistently with Option 3 of DR 431
245   // (see N1599).
246   struct uneq_allocator_base
247   {
248     typedef std::tr1::unordered_map<void*, int>   map_type;
249
250     // Avoid static initialization troubles and/or bad interactions
251     // with tests linking testsuite_allocator.o and playing globally
252     // with operator new/delete.
253     static map_type&
254     get_map()
255     {
256       static map_type alloc_map;
257       return alloc_map;
258     }
259   };
260
261   template<typename Tp>
262     class uneq_allocator
263     : private uneq_allocator_base
264     {
265     public:
266       typedef size_t                              size_type;
267       typedef ptrdiff_t                           difference_type;
268       typedef Tp*                                 pointer;
269       typedef const Tp*                           const_pointer;
270       typedef Tp&                                 reference;
271       typedef const Tp&                           const_reference;
272       typedef Tp                                  value_type;
273       
274       template<typename Tp1>
275         struct rebind
276         { typedef uneq_allocator<Tp1> other; };
277
278       uneq_allocator() throw()
279       : personality(0) { }
280
281       uneq_allocator(int person) throw()
282       : personality(person) { }
283       
284       template<typename Tp1>
285         uneq_allocator(const uneq_allocator<Tp1>& b) throw()
286         : personality(b.get_personality()) { }
287
288       int get_personality() const { return personality; }
289       
290       pointer
291       address(reference x) const { return &x; }
292     
293       const_pointer
294       address(const_reference x) const { return &x; }
295     
296       pointer
297       allocate(size_type n, const void* = 0)
298       { 
299         if (__builtin_expect(n > this->max_size(), false))
300           std::__throw_bad_alloc();
301         
302         pointer p = static_cast<Tp*>(::operator new(n * sizeof(Tp)));
303         try
304           {
305             get_map().insert(map_type::value_type(reinterpret_cast<void*>(p),
306                                                   personality));
307           }
308         catch(...)
309           {
310             ::operator delete(p);
311             __throw_exception_again;
312           }
313         return p;
314       }
315       
316       void
317       deallocate(pointer p, size_type)
318       {
319         assert( p );
320         
321         map_type::iterator it = get_map().find(reinterpret_cast<void*>(p));
322         assert( it != get_map().end() );
323
324         // Enforce requirements in Table 32 about deallocation vs
325         // allocator equality.
326         assert( it->second == personality );
327         
328         get_map().erase(it);
329         ::operator delete(p);
330       }
331       
332       size_type
333       max_size() const throw() 
334       { return size_t(-1) / sizeof(Tp); }
335       
336       void 
337       construct(pointer p, const Tp& val) 
338       { ::new(p) Tp(val); }
339     
340       void 
341       destroy(pointer p) { p->~Tp(); }
342
343     private:
344       // Not assignable...
345       uneq_allocator&
346       operator=(const uneq_allocator&);
347
348       // ... yet swappable!
349       friend inline void
350       swap(uneq_allocator& a, uneq_allocator& b)
351       { std::swap(a.personality, b.personality); } 
352       
353       template<typename Tp1>
354         friend inline bool
355         operator==(const uneq_allocator& a, const uneq_allocator<Tp1>& b)
356         { return a.personality == b.personality; }
357
358       template<typename Tp1>
359         friend inline bool
360         operator!=(const uneq_allocator& a, const uneq_allocator<Tp1>& b)
361         { return !(a == b); }
362       
363       int personality;
364     };
365
366
367   template<typename Tp>
368     class throw_allocator
369     {
370     public:
371       typedef std::size_t                         size_type;
372       typedef std::ptrdiff_t                      difference_type;
373       typedef Tp*                                 pointer;
374       typedef const Tp*                           const_pointer;
375       typedef Tp&                                 reference;
376       typedef const Tp&                           const_reference;
377       typedef Tp                                  value_type;
378       
379       template<typename Tp1>
380         struct rebind
381         { typedef throw_allocator<Tp1> other; };
382
383       throw_allocator() throw()
384       : count(size_type(-1)) { }
385
386       throw_allocator(size_type c) throw()
387       : count(c) { }
388       
389       template<typename Tp1>
390         throw_allocator(const throw_allocator<Tp1>& b) throw()
391         : count(b.get_count()) { }
392
393       size_type get_count() const { return count; }
394       
395       pointer
396       address(reference x) const { return &x; }
397     
398       const_pointer
399       address(const_reference x) const { return &x; }
400     
401       pointer
402       allocate(size_type n, const void* = 0)
403       {
404         if (count == 0)
405           throw std::bad_alloc();
406         
407         if (count != size_type(-1))
408           --count;
409         
410         return static_cast<Tp*>(::operator new(n * sizeof(Tp)));
411       }
412       
413       void
414       deallocate(pointer p, size_type)
415       { ::operator delete(p); }
416       
417       size_type
418       max_size() const throw() 
419       { return size_type(-1) / sizeof(Tp); }
420       
421       void 
422       construct(pointer p, const Tp& val) 
423       { ::new(p) Tp(val); }
424     
425       void 
426       destroy(pointer p) { p->~Tp(); }
427
428     private:
429       template<typename Tp1>
430         friend inline bool
431         operator==(const throw_allocator&, const throw_allocator<Tp1>&)
432         { return true; }
433
434       template<typename Tp1>
435         friend inline bool
436         operator!=(const throw_allocator&, const throw_allocator<Tp1>&)
437         { return false; }
438       
439       size_type count;
440     };
441 }; // namespace __gnu_test
442
443 #endif // _GLIBCXX_TESTSUITE_ALLOCATOR_H