Import gcc-4.4.1
[dragonfly.git] / contrib / gcc-4.4 / libstdc++-v3 / include / ext / mt_allocator.h
1 // MT-optimized allocator -*- C++ -*-
2
3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
4 // 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 3, 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 // Under Section 7 of GPL version 3, you are granted additional
18 // permissions described in the GCC Runtime Library Exception, version
19 // 3.1, as published by the Free Software Foundation.
20
21 // You should have received a copy of the GNU General Public License and
22 // a copy of the GCC Runtime Library Exception along with this program;
23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 // <http://www.gnu.org/licenses/>.
25
26 /** @file ext/mt_allocator.h
27  *  This file is a GNU extension to the Standard C++ Library.
28  */
29
30 #ifndef _MT_ALLOCATOR_H
31 #define _MT_ALLOCATOR_H 1
32
33 #include <new>
34 #include <cstdlib>
35 #include <bits/functexcept.h>
36 #include <ext/atomicity.h>
37 #include <bits/move.h>
38
39 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
40
41   using std::size_t;
42   using std::ptrdiff_t;
43
44   typedef void (*__destroy_handler)(void*);
45
46   /// Base class for pool object.
47   struct __pool_base
48   {
49     // Using short int as type for the binmap implies we are never
50     // caching blocks larger than 32768 with this allocator.
51     typedef unsigned short int _Binmap_type;
52
53     // Variables used to configure the behavior of the allocator,
54     // assigned and explained in detail below.
55     struct _Tune
56      {
57       // Compile time constants for the default _Tune values.
58       enum { _S_align = 8 };
59       enum { _S_max_bytes = 128 };
60       enum { _S_min_bin = 8 };
61       enum { _S_chunk_size = 4096 - 4 * sizeof(void*) };
62       enum { _S_max_threads = 4096 };
63       enum { _S_freelist_headroom = 10 };
64
65       // Alignment needed.
66       // NB: In any case must be >= sizeof(_Block_record), that
67       // is 4 on 32 bit machines and 8 on 64 bit machines.
68       size_t    _M_align;
69       
70       // Allocation requests (after round-up to power of 2) below
71       // this value will be handled by the allocator. A raw new/
72       // call will be used for requests larger than this value.
73       // NB: Must be much smaller than _M_chunk_size and in any
74       // case <= 32768.
75       size_t    _M_max_bytes; 
76
77       // Size in bytes of the smallest bin.
78       // NB: Must be a power of 2 and >= _M_align (and of course
79       // much smaller than _M_max_bytes).
80       size_t    _M_min_bin;
81
82       // In order to avoid fragmenting and minimize the number of
83       // new() calls we always request new memory using this
84       // value. Based on previous discussions on the libstdc++
85       // mailing list we have chosen the value below.
86       // See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
87       // NB: At least one order of magnitude > _M_max_bytes. 
88       size_t    _M_chunk_size;
89
90       // The maximum number of supported threads. For
91       // single-threaded operation, use one. Maximum values will
92       // vary depending on details of the underlying system. (For
93       // instance, Linux 2.4.18 reports 4070 in
94       // /proc/sys/kernel/threads-max, while Linux 2.6.6 reports
95       // 65534)
96       size_t    _M_max_threads;
97
98       // Each time a deallocation occurs in a threaded application
99       // we make sure that there are no more than
100       // _M_freelist_headroom % of used memory on the freelist. If
101       // the number of additional records is more than
102       // _M_freelist_headroom % of the freelist, we move these
103       // records back to the global pool.
104       size_t    _M_freelist_headroom;
105       
106       // Set to true forces all allocations to use new().
107       bool      _M_force_new; 
108       
109       explicit
110       _Tune()
111       : _M_align(_S_align), _M_max_bytes(_S_max_bytes), _M_min_bin(_S_min_bin),
112       _M_chunk_size(_S_chunk_size), _M_max_threads(_S_max_threads), 
113       _M_freelist_headroom(_S_freelist_headroom), 
114       _M_force_new(std::getenv("GLIBCXX_FORCE_NEW") ? true : false)
115       { }
116
117       explicit
118       _Tune(size_t __align, size_t __maxb, size_t __minbin, size_t __chunk, 
119             size_t __maxthreads, size_t __headroom, bool __force) 
120       : _M_align(__align), _M_max_bytes(__maxb), _M_min_bin(__minbin),
121       _M_chunk_size(__chunk), _M_max_threads(__maxthreads),
122       _M_freelist_headroom(__headroom), _M_force_new(__force)
123       { }
124     };
125     
126     struct _Block_address
127     {
128       void*                     _M_initial;
129       _Block_address*           _M_next;
130     };
131     
132     const _Tune&
133     _M_get_options() const
134     { return _M_options; }
135
136     void
137     _M_set_options(_Tune __t)
138     { 
139       if (!_M_init)
140         _M_options = __t;
141     }
142
143     bool
144     _M_check_threshold(size_t __bytes)
145     { return __bytes > _M_options._M_max_bytes || _M_options._M_force_new; }
146
147     size_t
148     _M_get_binmap(size_t __bytes)
149     { return _M_binmap[__bytes]; }
150
151     size_t
152     _M_get_align()
153     { return _M_options._M_align; }
154
155     explicit 
156     __pool_base() 
157     : _M_options(_Tune()), _M_binmap(NULL), _M_init(false) { }
158
159     explicit 
160     __pool_base(const _Tune& __options)
161     : _M_options(__options), _M_binmap(NULL), _M_init(false) { }
162
163   private:
164     explicit 
165     __pool_base(const __pool_base&);
166
167     __pool_base&
168     operator=(const __pool_base&);
169
170   protected:
171     // Configuration options.
172     _Tune                       _M_options;
173     
174     _Binmap_type*               _M_binmap;
175
176     // Configuration of the pool object via _M_options can happen
177     // after construction but before initialization. After
178     // initialization is complete, this variable is set to true.
179     bool                        _M_init;
180   };
181
182
183   /**
184    *  @brief  Data describing the underlying memory pool, parameterized on
185    *  threading support.
186    */
187   template<bool _Thread>
188     class __pool;
189
190   /// Specialization for single thread.
191   template<>
192     class __pool<false> : public __pool_base
193     {
194     public:
195       union _Block_record
196       {
197         // Points to the block_record of the next free block.
198         _Block_record*                  _M_next;
199       };
200
201       struct _Bin_record
202       {
203         // An "array" of pointers to the first free block.
204         _Block_record**                 _M_first;
205
206         // A list of the initial addresses of all allocated blocks.
207         _Block_address*                 _M_address;
208       };
209       
210       void
211       _M_initialize_once()
212       {
213         if (__builtin_expect(_M_init == false, false))
214           _M_initialize();
215       }
216
217       void
218       _M_destroy() throw();
219
220       char* 
221       _M_reserve_block(size_t __bytes, const size_t __thread_id);
222     
223       void
224       _M_reclaim_block(char* __p, size_t __bytes);
225     
226       size_t 
227       _M_get_thread_id() { return 0; }
228       
229       const _Bin_record&
230       _M_get_bin(size_t __which)
231       { return _M_bin[__which]; }
232       
233       void
234       _M_adjust_freelist(const _Bin_record&, _Block_record*, size_t)
235       { }
236
237       explicit __pool() 
238       : _M_bin(NULL), _M_bin_size(1) { }
239
240       explicit __pool(const __pool_base::_Tune& __tune) 
241       : __pool_base(__tune), _M_bin(NULL), _M_bin_size(1) { }
242
243     private:
244       // An "array" of bin_records each of which represents a specific
245       // power of 2 size. Memory to this "array" is allocated in
246       // _M_initialize().
247       _Bin_record*               _M_bin;
248       
249       // Actual value calculated in _M_initialize().
250       size_t                    _M_bin_size;     
251
252       void
253       _M_initialize();
254   };
255  
256 #ifdef __GTHREADS
257   /// Specialization for thread enabled, via gthreads.h.
258   template<>
259     class __pool<true> : public __pool_base
260     {
261     public:
262       // Each requesting thread is assigned an id ranging from 1 to
263       // _S_max_threads. Thread id 0 is used as a global memory pool.
264       // In order to get constant performance on the thread assignment
265       // routine, we keep a list of free ids. When a thread first
266       // requests memory we remove the first record in this list and
267       // stores the address in a __gthread_key. When initializing the
268       // __gthread_key we specify a destructor. When this destructor
269       // (i.e. the thread dies) is called, we return the thread id to
270       // the front of this list.
271       struct _Thread_record
272       {
273         // Points to next free thread id record. NULL if last record in list.
274         _Thread_record*                 _M_next;
275         
276         // Thread id ranging from 1 to _S_max_threads.
277         size_t                          _M_id;
278       };
279       
280       union _Block_record
281       {
282         // Points to the block_record of the next free block.
283         _Block_record*                  _M_next;
284         
285         // The thread id of the thread which has requested this block.
286         size_t                          _M_thread_id;
287       };
288       
289       struct _Bin_record
290       {
291         // An "array" of pointers to the first free block for each
292         // thread id. Memory to this "array" is allocated in
293         // _S_initialize() for _S_max_threads + global pool 0.
294         _Block_record**                 _M_first;
295         
296         // A list of the initial addresses of all allocated blocks.
297         _Block_address*                 _M_address;
298
299         // An "array" of counters used to keep track of the amount of
300         // blocks that are on the freelist/used for each thread id.
301         // - Note that the second part of the allocated _M_used "array"
302         //   actually hosts (atomic) counters of reclaimed blocks:  in
303         //   _M_reserve_block and in _M_reclaim_block those numbers are
304         //   subtracted from the first ones to obtain the actual size
305         //   of the "working set" of the given thread.
306         // - Memory to these "arrays" is allocated in _S_initialize()
307         //   for _S_max_threads + global pool 0.
308         size_t*                         _M_free;
309         size_t*                         _M_used;
310         
311         // Each bin has its own mutex which is used to ensure data
312         // integrity while changing "ownership" on a block.  The mutex
313         // is initialized in _S_initialize().
314         __gthread_mutex_t*              _M_mutex;
315       };
316       
317       // XXX GLIBCXX_ABI Deprecated
318       void
319       _M_initialize(__destroy_handler);
320
321       void
322       _M_initialize_once()
323       {
324         if (__builtin_expect(_M_init == false, false))
325           _M_initialize();
326       }
327
328       void
329       _M_destroy() throw();
330
331       char* 
332       _M_reserve_block(size_t __bytes, const size_t __thread_id);
333     
334       void
335       _M_reclaim_block(char* __p, size_t __bytes);
336     
337       const _Bin_record&
338       _M_get_bin(size_t __which)
339       { return _M_bin[__which]; }
340       
341       void
342       _M_adjust_freelist(const _Bin_record& __bin, _Block_record* __block, 
343                          size_t __thread_id)
344       {
345         if (__gthread_active_p())
346           {
347             __block->_M_thread_id = __thread_id;
348             --__bin._M_free[__thread_id];
349             ++__bin._M_used[__thread_id];
350           }
351       }
352
353       // XXX GLIBCXX_ABI Deprecated
354       void 
355       _M_destroy_thread_key(void*);
356
357       size_t 
358       _M_get_thread_id();
359
360       explicit __pool() 
361       : _M_bin(NULL), _M_bin_size(1), _M_thread_freelist(NULL) 
362       { }
363
364       explicit __pool(const __pool_base::_Tune& __tune) 
365       : __pool_base(__tune), _M_bin(NULL), _M_bin_size(1), 
366       _M_thread_freelist(NULL) 
367       { }
368
369     private:
370       // An "array" of bin_records each of which represents a specific
371       // power of 2 size. Memory to this "array" is allocated in
372       // _M_initialize().
373       _Bin_record*              _M_bin;
374
375       // Actual value calculated in _M_initialize().
376       size_t                    _M_bin_size;
377
378       _Thread_record*           _M_thread_freelist;
379       void*                     _M_thread_freelist_initial;
380
381       void
382       _M_initialize();
383     };
384 #endif
385
386   template<template <bool> class _PoolTp, bool _Thread>
387     struct __common_pool
388     {
389       typedef _PoolTp<_Thread>          pool_type;
390       
391       static pool_type&
392       _S_get_pool()
393       { 
394         static pool_type _S_pool;
395         return _S_pool;
396       }
397     };
398
399   template<template <bool> class _PoolTp, bool _Thread>
400     struct __common_pool_base;
401
402   template<template <bool> class _PoolTp>
403     struct __common_pool_base<_PoolTp, false> 
404     : public __common_pool<_PoolTp, false>
405     {
406       using  __common_pool<_PoolTp, false>::_S_get_pool;
407
408       static void
409       _S_initialize_once()
410       {
411         static bool __init;
412         if (__builtin_expect(__init == false, false))
413           {
414             _S_get_pool()._M_initialize_once(); 
415             __init = true;
416           }
417       }
418     };
419
420 #ifdef __GTHREADS
421   template<template <bool> class _PoolTp>
422     struct __common_pool_base<_PoolTp, true>
423     : public __common_pool<_PoolTp, true>
424     {
425       using  __common_pool<_PoolTp, true>::_S_get_pool;
426       
427       static void
428       _S_initialize() 
429       { _S_get_pool()._M_initialize_once(); }
430
431       static void
432       _S_initialize_once()
433       { 
434         static bool __init;
435         if (__builtin_expect(__init == false, false))
436           {
437             if (__gthread_active_p())
438               {
439                 // On some platforms, __gthread_once_t is an aggregate.
440                 static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
441                 __gthread_once(&__once, _S_initialize);
442               }
443
444             // Double check initialization. May be necessary on some
445             // systems for proper construction when not compiling with
446             // thread flags.
447             _S_get_pool()._M_initialize_once(); 
448             __init = true;
449           }
450       }
451     };
452 #endif
453
454   /// Policy for shared __pool objects.
455   template<template <bool> class _PoolTp, bool _Thread>
456     struct __common_pool_policy : public __common_pool_base<_PoolTp, _Thread>
457     {
458       template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, 
459                bool _Thread1 = _Thread>
460         struct _M_rebind
461         { typedef __common_pool_policy<_PoolTp1, _Thread1> other; };
462
463       using  __common_pool_base<_PoolTp, _Thread>::_S_get_pool;
464       using  __common_pool_base<_PoolTp, _Thread>::_S_initialize_once;
465   };
466  
467
468   template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
469     struct __per_type_pool
470     {
471       typedef _Tp                       value_type;
472       typedef _PoolTp<_Thread>          pool_type;
473       
474       static pool_type&
475       _S_get_pool()
476       { 
477         // Sane defaults for the _PoolTp.
478         typedef typename pool_type::_Block_record _Block_record;
479         const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record)
480                                    ? __alignof__(_Tp) : sizeof(_Block_record));
481
482         typedef typename __pool_base::_Tune _Tune;
483         static _Tune _S_tune(__a, sizeof(_Tp) * 64,
484                              sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a,
485                              sizeof(_Tp) * size_t(_Tune::_S_chunk_size),
486                              _Tune::_S_max_threads,
487                              _Tune::_S_freelist_headroom,
488                              std::getenv("GLIBCXX_FORCE_NEW") ? true : false);
489         static pool_type _S_pool(_S_tune);
490         return _S_pool;
491       }
492     };
493
494   template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
495     struct __per_type_pool_base;
496
497   template<typename _Tp, template <bool> class _PoolTp>
498     struct __per_type_pool_base<_Tp, _PoolTp, false> 
499     : public __per_type_pool<_Tp, _PoolTp, false> 
500     {
501       using  __per_type_pool<_Tp, _PoolTp, false>::_S_get_pool;
502
503       static void
504       _S_initialize_once()
505       {
506         static bool __init;
507         if (__builtin_expect(__init == false, false))
508           {
509             _S_get_pool()._M_initialize_once(); 
510             __init = true;
511           }
512       }
513     };
514
515  #ifdef __GTHREADS
516  template<typename _Tp, template <bool> class _PoolTp>
517     struct __per_type_pool_base<_Tp, _PoolTp, true> 
518     : public __per_type_pool<_Tp, _PoolTp, true> 
519     {
520       using  __per_type_pool<_Tp, _PoolTp, true>::_S_get_pool;
521
522       static void
523       _S_initialize() 
524       { _S_get_pool()._M_initialize_once(); }
525
526       static void
527       _S_initialize_once()
528       { 
529         static bool __init;
530         if (__builtin_expect(__init == false, false))
531           {
532             if (__gthread_active_p())
533               {
534                 // On some platforms, __gthread_once_t is an aggregate.
535                 static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
536                 __gthread_once(&__once, _S_initialize);
537               }
538
539             // Double check initialization. May be necessary on some
540             // systems for proper construction when not compiling with
541             // thread flags.
542             _S_get_pool()._M_initialize_once(); 
543             __init = true;
544           }
545       }
546     };
547 #endif
548
549   /// Policy for individual __pool objects.
550   template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
551     struct __per_type_pool_policy 
552     : public __per_type_pool_base<_Tp, _PoolTp, _Thread>
553     {
554       template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp, 
555                bool _Thread1 = _Thread>
556         struct _M_rebind
557         { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; };
558
559       using  __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_get_pool;
560       using  __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_initialize_once;
561   };
562
563
564   /// Base class for _Tp dependent member functions.
565   template<typename _Tp>
566     class __mt_alloc_base 
567     {
568     public:
569       typedef size_t                    size_type;
570       typedef ptrdiff_t                 difference_type;
571       typedef _Tp*                      pointer;
572       typedef const _Tp*                const_pointer;
573       typedef _Tp&                      reference;
574       typedef const _Tp&                const_reference;
575       typedef _Tp                       value_type;
576
577       pointer
578       address(reference __x) const
579       { return &__x; }
580
581       const_pointer
582       address(const_reference __x) const
583       { return &__x; }
584
585       size_type
586       max_size() const throw() 
587       { return size_t(-1) / sizeof(_Tp); }
588
589       // _GLIBCXX_RESOLVE_LIB_DEFECTS
590       // 402. wrong new expression in [some_] allocator::construct
591       void 
592       construct(pointer __p, const _Tp& __val) 
593       { ::new((void *)__p) _Tp(__val); }
594
595 #ifdef __GXX_EXPERIMENTAL_CXX0X__
596       template<typename... _Args>
597         void
598         construct(pointer __p, _Args&&... __args)
599         { ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); }
600 #endif
601
602       void 
603       destroy(pointer __p) { __p->~_Tp(); }
604     };
605
606 #ifdef __GTHREADS
607 #define __thread_default true
608 #else
609 #define __thread_default false
610 #endif
611
612   /**
613    *  @brief  This is a fixed size (power of 2) allocator which - when
614    *  compiled with thread support - will maintain one freelist per
615    *  size per thread plus a "global" one. Steps are taken to limit
616    *  the per thread freelist sizes (by returning excess back to
617    *  the "global" list).
618    *  @ingroup allocators
619    *
620    *  Further details:
621    *  http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt12ch32.html
622    */
623   template<typename _Tp, 
624            typename _Poolp = __common_pool_policy<__pool, __thread_default> >
625     class __mt_alloc : public __mt_alloc_base<_Tp>
626     {
627     public:
628       typedef size_t                            size_type;
629       typedef ptrdiff_t                         difference_type;
630       typedef _Tp*                              pointer;
631       typedef const _Tp*                        const_pointer;
632       typedef _Tp&                              reference;
633       typedef const _Tp&                        const_reference;
634       typedef _Tp                               value_type;
635       typedef _Poolp                            __policy_type;
636       typedef typename _Poolp::pool_type        __pool_type;
637
638       template<typename _Tp1, typename _Poolp1 = _Poolp>
639         struct rebind
640         { 
641           typedef typename _Poolp1::template _M_rebind<_Tp1>::other pol_type;
642           typedef __mt_alloc<_Tp1, pol_type> other;
643         };
644
645       __mt_alloc() throw() { }
646
647       __mt_alloc(const __mt_alloc&) throw() { }
648
649       template<typename _Tp1, typename _Poolp1>
650         __mt_alloc(const __mt_alloc<_Tp1, _Poolp1>&) throw() { }
651
652       ~__mt_alloc() throw() { }
653
654       pointer
655       allocate(size_type __n, const void* = 0);
656
657       void
658       deallocate(pointer __p, size_type __n);
659
660       const __pool_base::_Tune
661       _M_get_options()
662       { 
663         // Return a copy, not a reference, for external consumption.
664         return __policy_type::_S_get_pool()._M_get_options();
665       }
666       
667       void
668       _M_set_options(__pool_base::_Tune __t)
669       { __policy_type::_S_get_pool()._M_set_options(__t); }
670     };
671
672   template<typename _Tp, typename _Poolp>
673     typename __mt_alloc<_Tp, _Poolp>::pointer
674     __mt_alloc<_Tp, _Poolp>::
675     allocate(size_type __n, const void*)
676     {
677       if (__builtin_expect(__n > this->max_size(), false))
678         std::__throw_bad_alloc();
679
680       __policy_type::_S_initialize_once();
681
682       // Requests larger than _M_max_bytes are handled by operator
683       // new/delete directly.
684       __pool_type& __pool = __policy_type::_S_get_pool();
685       const size_t __bytes = __n * sizeof(_Tp);
686       if (__pool._M_check_threshold(__bytes))
687         {
688           void* __ret = ::operator new(__bytes);
689           return static_cast<_Tp*>(__ret);
690         }
691       
692       // Round up to power of 2 and figure out which bin to use.
693       const size_t __which = __pool._M_get_binmap(__bytes);
694       const size_t __thread_id = __pool._M_get_thread_id();
695       
696       // Find out if we have blocks on our freelist.  If so, go ahead
697       // and use them directly without having to lock anything.
698       char* __c;
699       typedef typename __pool_type::_Bin_record _Bin_record;
700       const _Bin_record& __bin = __pool._M_get_bin(__which);
701       if (__bin._M_first[__thread_id])
702         {
703           // Already reserved.
704           typedef typename __pool_type::_Block_record _Block_record;
705           _Block_record* __block = __bin._M_first[__thread_id];
706           __bin._M_first[__thread_id] = __block->_M_next;
707           
708           __pool._M_adjust_freelist(__bin, __block, __thread_id);
709           __c = reinterpret_cast<char*>(__block) + __pool._M_get_align();
710         }
711       else
712         {
713           // Null, reserve.
714           __c = __pool._M_reserve_block(__bytes, __thread_id);
715         }
716       return static_cast<_Tp*>(static_cast<void*>(__c));
717     }
718   
719   template<typename _Tp, typename _Poolp>
720     void
721     __mt_alloc<_Tp, _Poolp>::
722     deallocate(pointer __p, size_type __n)
723     {
724       if (__builtin_expect(__p != 0, true))
725         {
726           // Requests larger than _M_max_bytes are handled by
727           // operators new/delete directly.
728           __pool_type& __pool = __policy_type::_S_get_pool();
729           const size_t __bytes = __n * sizeof(_Tp);
730           if (__pool._M_check_threshold(__bytes))
731             ::operator delete(__p);
732           else
733             __pool._M_reclaim_block(reinterpret_cast<char*>(__p), __bytes);
734         }
735     }
736   
737   template<typename _Tp, typename _Poolp>
738     inline bool
739     operator==(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&)
740     { return true; }
741   
742   template<typename _Tp, typename _Poolp>
743     inline bool
744     operator!=(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&)
745     { return false; }
746
747 #undef __thread_default
748
749 _GLIBCXX_END_NAMESPACE
750
751 #endif