Whole document tree stl_alloc.hGo to the documentation of this file.00001 // Allocators -*- C++ -*- 00002 00003 // Copyright (C) 2001 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 2, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // You should have received a copy of the GNU General Public License along 00017 // with this library; see the file COPYING. If not, write to the Free 00018 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 00019 // USA. 00020 00021 // As a special exception, you may use this file as part of a free software 00022 // library without restriction. Specifically, if other files instantiate 00023 // templates or use macros or inline functions from this file, or you compile 00024 // this file and link it with other files to produce an executable, this 00025 // file does not by itself cause the resulting executable to be covered by 00026 // the GNU General Public License. This exception does not however 00027 // invalidate any other reasons why the executable file might be covered by 00028 // the GNU General Public License. 00029 00030 /* 00031 * Copyright (c) 1996-1997 00032 * Silicon Graphics Computer Systems, Inc. 00033 * 00034 * Permission to use, copy, modify, distribute and sell this software 00035 * and its documentation for any purpose is hereby granted without fee, 00036 * provided that the above copyright notice appear in all copies and 00037 * that both that copyright notice and this permission notice appear 00038 * in supporting documentation. Silicon Graphics makes no 00039 * representations about the suitability of this software for any 00040 * purpose. It is provided "as is" without express or implied warranty. 00041 */ 00042 00043 /* NOTE: This is an internal header file, included by other STL headers. 00044 * You should not attempt to use it directly. 00045 */ 00046 00047 #ifndef __SGI_STL_INTERNAL_ALLOC_H 00048 #define __SGI_STL_INTERNAL_ALLOC_H 00049 00050 // This implements some standard node allocators. These are 00051 // NOT the same as the allocators in the C++ draft standard or in 00052 // in the original STL. They do not encapsulate different pointer 00053 // types; indeed we assume that there is only one pointer type. 00054 // The allocation primitives are intended to allocate individual objects, 00055 // not larger arenas as with the original STL allocators. 00056 00057 #include <bits/functexcept.h> // for __throw_bad_alloc 00058 #include <bits/std_cstddef.h> 00059 #include <bits/std_cstdlib.h> 00060 #include <bits/std_cstring.h> 00061 #include <bits/std_cassert.h> 00062 #ifndef __RESTRICT 00063 # define __RESTRICT 00064 #endif 00065 00066 #ifdef __STL_THREADS 00067 # include <bits/stl_threads.h> 00068 # define __NODE_ALLOCATOR_THREADS true 00069 # ifdef __STL_SGI_THREADS 00070 // We test whether threads are in use before locking. 00071 // Perhaps this should be moved into stl_threads.h, but that 00072 // probably makes it harder to avoid the procedure call when 00073 // it isn't needed. 00074 extern "C" { 00075 extern int __us_rsthread_malloc; 00076 } 00077 // The above is copied from malloc.h. Including <malloc.h> 00078 // would be cleaner but fails with certain levels of standard 00079 // conformance. 00080 # define __NODE_ALLOCATOR_LOCK if (threads && __us_rsthread_malloc) \ 00081 { _S_node_allocator_lock._M_acquire_lock(); } 00082 # define __NODE_ALLOCATOR_UNLOCK if (threads && __us_rsthread_malloc) \ 00083 { _S_node_allocator_lock._M_release_lock(); } 00084 # else /* !__STL_SGI_THREADS */ 00085 # define __NODE_ALLOCATOR_LOCK \ 00086 { if (threads) _S_node_allocator_lock._M_acquire_lock(); } 00087 # define __NODE_ALLOCATOR_UNLOCK \ 00088 { if (threads) _S_node_allocator_lock._M_release_lock(); } 00089 # endif 00090 #else 00091 // Thread-unsafe 00092 # define __NODE_ALLOCATOR_LOCK 00093 # define __NODE_ALLOCATOR_UNLOCK 00094 # define __NODE_ALLOCATOR_THREADS false 00095 #endif 00096 00097 namespace std 00098 { 00099 00100 // Malloc-based allocator. Typically slower than default alloc below. 00101 // Typically thread-safe and more storage efficient. 00102 template <int __inst> 00103 class __malloc_alloc_template { 00104 00105 private: 00106 00107 static void* _S_oom_malloc(size_t); 00108 static void* _S_oom_realloc(void*, size_t); 00109 static void (* __malloc_alloc_oom_handler)(); 00110 00111 public: 00112 00113 static void* allocate(size_t __n) 00114 { 00115 void* __result = malloc(__n); 00116 if (0 == __result) __result = _S_oom_malloc(__n); 00117 return __result; 00118 } 00119 00120 static void deallocate(void* __p, size_t /* __n */) 00121 { 00122 free(__p); 00123 } 00124 00125 static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz) 00126 { 00127 void* __result = realloc(__p, __new_sz); 00128 if (0 == __result) __result = _S_oom_realloc(__p, __new_sz); 00129 return __result; 00130 } 00131 00132 static void (* __set_malloc_handler(void (*__f)()))() 00133 { 00134 void (* __old)() = __malloc_alloc_oom_handler; 00135 __malloc_alloc_oom_handler = __f; 00136 return(__old); 00137 } 00138 00139 }; 00140 00141 // malloc_alloc out-of-memory handling 00142 00143 template <int __inst> 00144 void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0; 00145 00146 template <int __inst> 00147 void* 00148 __malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n) 00149 { 00150 void (* __my_malloc_handler)(); 00151 void* __result; 00152 00153 for (;;) { 00154 __my_malloc_handler = __malloc_alloc_oom_handler; 00155 if (0 == __my_malloc_handler) { std::__throw_bad_alloc(); } 00156 (*__my_malloc_handler)(); 00157 __result = malloc(__n); 00158 if (__result) return(__result); 00159 } 00160 } 00161 00162 template <int __inst> 00163 void* __malloc_alloc_template<__inst>::_S_oom_realloc(void* __p, size_t __n) 00164 { 00165 void (* __my_malloc_handler)(); 00166 void* __result; 00167 00168 for (;;) { 00169 __my_malloc_handler = __malloc_alloc_oom_handler; 00170 if (0 == __my_malloc_handler) { std::__throw_bad_alloc(); } 00171 (*__my_malloc_handler)(); 00172 __result = realloc(__p, __n); 00173 if (__result) return(__result); 00174 } 00175 } 00176 00177 typedef __malloc_alloc_template<0> malloc_alloc; 00178 00179 template<class _Tp, class _Alloc> 00180 class simple_alloc { 00181 00182 public: 00183 static _Tp* allocate(size_t __n) 00184 { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); } 00185 static _Tp* allocate(void) 00186 { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); } 00187 static void deallocate(_Tp* __p, size_t __n) 00188 { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); } 00189 static void deallocate(_Tp* __p) 00190 { _Alloc::deallocate(__p, sizeof (_Tp)); } 00191 }; 00192 00193 // Allocator adaptor to check size arguments for debugging. 00194 // Reports errors using assert. Checking can be disabled with 00195 // NDEBUG, but it's far better to just use the underlying allocator 00196 // instead when no checking is desired. 00197 // There is some evidence that this can confuse Purify. 00198 template <class _Alloc> 00199 class debug_alloc { 00200 00201 private: 00202 00203 enum {_S_extra = 8}; // Size of space used to store size. Note 00204 // that this must be large enough to preserve 00205 // alignment. 00206 00207 public: 00208 00209 static void* allocate(size_t __n) 00210 { 00211 char* __result = (char*)_Alloc::allocate(__n + (int) _S_extra); 00212 *(size_t*)__result = __n; 00213 return __result + (int) _S_extra; 00214 } 00215 00216 static void deallocate(void* __p, size_t __n) 00217 { 00218 char* __real_p = (char*)__p - (int) _S_extra; 00219 assert(*(size_t*)__real_p == __n); 00220 _Alloc::deallocate(__real_p, __n + (int) _S_extra); 00221 } 00222 00223 static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz) 00224 { 00225 char* __real_p = (char*)__p - (int) _S_extra; 00226 assert(*(size_t*)__real_p == __old_sz); 00227 char* __result = (char*) 00228 _Alloc::reallocate(__real_p, __old_sz + (int) _S_extra, 00229 __new_sz + (int) _S_extra); 00230 *(size_t*)__result = __new_sz; 00231 return __result + (int) _S_extra; 00232 } 00233 00234 }; 00235 00236 00237 # ifdef __USE_MALLOC 00238 00239 typedef malloc_alloc alloc; 00240 typedef malloc_alloc single_client_alloc; 00241 00242 # else 00243 00244 00245 // Default node allocator. 00246 // With a reasonable compiler, this should be roughly as fast as the 00247 // original STL class-specific allocators, but with less fragmentation. 00248 // Default_alloc_template parameters are experimental and MAY 00249 // DISAPPEAR in the future. Clients should just use alloc for now. 00250 // 00251 // Important implementation properties: 00252 // 1. If the client request an object of size > _MAX_BYTES, the resulting 00253 // object will be obtained directly from malloc. 00254 // 2. In all other cases, we allocate an object of size exactly 00255 // _S_round_up(requested_size). Thus the client has enough size 00256 // information that we can return the object to the proper free list 00257 // without permanently losing part of the object. 00258 // 00259 00260 // The first template parameter specifies whether more than one thread 00261 // may use this allocator. It is safe to allocate an object from 00262 // one instance of a default_alloc and deallocate it with another 00263 // one. This effectively transfers its ownership to the second one. 00264 // This may have undesirable effects on reference locality. 00265 // The second parameter is unreferenced and serves only to allow the 00266 // creation of multiple default_alloc instances. 00267 // Node that containers built on different allocator instances have 00268 // different types, limiting the utility of this approach. 00269 00270 template <bool threads, int inst> 00271 class __default_alloc_template { 00272 00273 private: 00274 // Really we should use static const int x = N 00275 // instead of enum { x = N }, but few compilers accept the former. 00276 enum {_ALIGN = 8}; 00277 enum {_MAX_BYTES = 128}; 00278 enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN 00279 static size_t 00280 _S_round_up(size_t __bytes) 00281 { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); } 00282 00283 union _Obj { 00284 union _Obj* _M_free_list_link; 00285 char _M_client_data[1]; /* The client sees this. */ 00286 }; 00287 00288 static _Obj* __STL_VOLATILE _S_free_list[]; 00289 // Specifying a size results in duplicate def for 4.1 00290 static size_t _S_freelist_index(size_t __bytes) { 00291 return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1); 00292 } 00293 00294 // Returns an object of size __n, and optionally adds to size __n free list. 00295 static void* _S_refill(size_t __n); 00296 // Allocates a chunk for nobjs of size size. nobjs may be reduced 00297 // if it is inconvenient to allocate the requested number. 00298 static char* _S_chunk_alloc(size_t __size, int& __nobjs); 00299 00300 // Chunk allocation state. 00301 static char* _S_start_free; 00302 static char* _S_end_free; 00303 static size_t _S_heap_size; 00304 00305 # ifdef __STL_THREADS 00306 static _STL_mutex_lock _S_node_allocator_lock; 00307 # endif 00308 00309 // It would be nice to use _STL_auto_lock here. But we 00310 // don't need the NULL check. And we do need a test whether 00311 // threads have actually been started. 00312 class _Lock; 00313 friend class _Lock; 00314 class _Lock { 00315 public: 00316 _Lock() { __NODE_ALLOCATOR_LOCK; } 00317 ~_Lock() { __NODE_ALLOCATOR_UNLOCK; } 00318 }; 00319 00320 public: 00321 00322 /* __n must be > 0 */ 00323 static void* allocate(size_t __n) 00324 { 00325 void* __ret = 0; 00326 00327 if (__n > (size_t) _MAX_BYTES) { 00328 __ret = malloc_alloc::allocate(__n); 00329 } 00330 else { 00331 _Obj* __STL_VOLATILE* __my_free_list 00332 = _S_free_list + _S_freelist_index(__n); 00333 // Acquire the lock here with a constructor call. 00334 // This ensures that it is released in exit or during stack 00335 // unwinding. 00336 # ifndef _NOTHREADS 00337 /*REFERENCED*/ 00338 _Lock __lock_instance; 00339 # endif 00340 _Obj* __RESTRICT __result = *__my_free_list; 00341 if (__result == 0) 00342 __ret = _S_refill(_S_round_up(__n)); 00343 else { 00344 *__my_free_list = __result -> _M_free_list_link; 00345 __ret = __result; 00346 } 00347 } 00348 00349 return __ret; 00350 }; 00351 00352 /* __p may not be 0 */ 00353 static void deallocate(void* __p, size_t __n) 00354 { 00355 if (__n > (size_t) _MAX_BYTES) 00356 malloc_alloc::deallocate(__p, __n); 00357 else { 00358 _Obj* __STL_VOLATILE* __my_free_list 00359 = _S_free_list + _S_freelist_index(__n); 00360 _Obj* __q = (_Obj*)__p; 00361 00362 // acquire lock 00363 # ifndef _NOTHREADS 00364 /*REFERENCED*/ 00365 _Lock __lock_instance; 00366 # endif /* _NOTHREADS */ 00367 __q -> _M_free_list_link = *__my_free_list; 00368 *__my_free_list = __q; 00369 // lock is released here 00370 } 00371 } 00372 00373 static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz); 00374 00375 } ; 00376 00377 typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc; 00378 typedef __default_alloc_template<false, 0> single_client_alloc; 00379 00380 template <bool __threads, int __inst> 00381 inline bool operator==(const __default_alloc_template<__threads, __inst>&, 00382 const __default_alloc_template<__threads, __inst>&) 00383 { 00384 return true; 00385 } 00386 00387 template <bool __threads, int __inst> 00388 inline bool operator!=(const __default_alloc_template<__threads, __inst>&, 00389 const __default_alloc_template<__threads, __inst>&) 00390 { 00391 return false; 00392 } 00393 00394 00395 00396 /* We allocate memory in large chunks in order to avoid fragmenting */ 00397 /* the malloc heap too much. */ 00398 /* We assume that size is properly aligned. */ 00399 /* We hold the allocation lock. */ 00400 template <bool __threads, int __inst> 00401 char* 00402 __default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, 00403 int& __nobjs) 00404 { 00405 char* __result; 00406 size_t __total_bytes = __size * __nobjs; 00407 size_t __bytes_left = _S_end_free - _S_start_free; 00408 00409 if (__bytes_left >= __total_bytes) { 00410 __result = _S_start_free; 00411 _S_start_free += __total_bytes; 00412 return(__result); 00413 } else if (__bytes_left >= __size) { 00414 __nobjs = (int)(__bytes_left/__size); 00415 __total_bytes = __size * __nobjs; 00416 __result = _S_start_free; 00417 _S_start_free += __total_bytes; 00418 return(__result); 00419 } else { 00420 size_t __bytes_to_get = 00421 2 * __total_bytes + _S_round_up(_S_heap_size >> 4); 00422 // Try to make use of the left-over piece. 00423 if (__bytes_left > 0) { 00424 _Obj* __STL_VOLATILE* __my_free_list = 00425 _S_free_list + _S_freelist_index(__bytes_left); 00426 00427 ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list; 00428 *__my_free_list = (_Obj*)_S_start_free; 00429 } 00430 _S_start_free = (char*)malloc(__bytes_to_get); 00431 if (0 == _S_start_free) { 00432 size_t __i; 00433 _Obj* __STL_VOLATILE* __my_free_list; 00434 _Obj* __p; 00435 // Try to make do with what we have. That can't 00436 // hurt. We do not try smaller requests, since that tends 00437 // to result in disaster on multi-process machines. 00438 for (__i = __size; 00439 __i <= (size_t) _MAX_BYTES; 00440 __i += (size_t) _ALIGN) { 00441 __my_free_list = _S_free_list + _S_freelist_index(__i); 00442 __p = *__my_free_list; 00443 if (0 != __p) { 00444 *__my_free_list = __p -> _M_free_list_link; 00445 _S_start_free = (char*)__p; 00446 _S_end_free = _S_start_free + __i; 00447 return(_S_chunk_alloc(__size, __nobjs)); 00448 // Any leftover piece will eventually make it to the 00449 // right free list. 00450 } 00451 } 00452 _S_end_free = 0; // In case of exception. 00453 _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get); 00454 // This should either throw an 00455 // exception or remedy the situation. Thus we assume it 00456 // succeeded. 00457 } 00458 _S_heap_size += __bytes_to_get; 00459 _S_end_free = _S_start_free + __bytes_to_get; 00460 return(_S_chunk_alloc(__size, __nobjs)); 00461 } 00462 } 00463 00464 00465 /* Returns an object of size __n, and optionally adds to size __n free list.*/ 00466 /* We assume that __n is properly aligned. */ 00467 /* We hold the allocation lock. */ 00468 template <bool __threads, int __inst> 00469 void* 00470 __default_alloc_template<__threads, __inst>::_S_refill(size_t __n) 00471 { 00472 int __nobjs = 20; 00473 char* __chunk = _S_chunk_alloc(__n, __nobjs); 00474 _Obj* __STL_VOLATILE* __my_free_list; 00475 _Obj* __result; 00476 _Obj* __current_obj; 00477 _Obj* __next_obj; 00478 int __i; 00479 00480 if (1 == __nobjs) return(__chunk); 00481 __my_free_list = _S_free_list + _S_freelist_index(__n); 00482 00483 /* Build free list in chunk */ 00484 __result = (_Obj*)__chunk; 00485 *__my_free_list = __next_obj = (_Obj*)(__chunk + __n); 00486 for (__i = 1; ; __i++) { 00487 __current_obj = __next_obj; 00488 __next_obj = (_Obj*)((char*)__next_obj + __n); 00489 if (__nobjs - 1 == __i) { 00490 __current_obj -> _M_free_list_link = 0; 00491 break; 00492 } else { 00493 __current_obj -> _M_free_list_link = __next_obj; 00494 } 00495 } 00496 return(__result); 00497 } 00498 00499 template <bool threads, int inst> 00500 void* 00501 __default_alloc_template<threads, inst>::reallocate(void* __p, 00502 size_t __old_sz, 00503 size_t __new_sz) 00504 { 00505 void* __result; 00506 size_t __copy_sz; 00507 00508 if (__old_sz > (size_t) _MAX_BYTES && __new_sz > (size_t) _MAX_BYTES) { 00509 return(realloc(__p, __new_sz)); 00510 } 00511 if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p); 00512 __result = allocate(__new_sz); 00513 __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz; 00514 memcpy(__result, __p, __copy_sz); 00515 deallocate(__p, __old_sz); 00516 return(__result); 00517 } 00518 00519 #ifdef __STL_THREADS 00520 template <bool __threads, int __inst> 00521 _STL_mutex_lock 00522 __default_alloc_template<__threads, __inst>::_S_node_allocator_lock 00523 __STL_MUTEX_INITIALIZER; 00524 #endif 00525 00526 00527 template <bool __threads, int __inst> 00528 char* __default_alloc_template<__threads, __inst>::_S_start_free = 0; 00529 00530 template <bool __threads, int __inst> 00531 char* __default_alloc_template<__threads, __inst>::_S_end_free = 0; 00532 00533 template <bool __threads, int __inst> 00534 size_t __default_alloc_template<__threads, __inst>::_S_heap_size = 0; 00535 00536 template <bool __threads, int __inst> 00537 typename __default_alloc_template<__threads, __inst>::_Obj* __STL_VOLATILE 00538 __default_alloc_template<__threads, __inst> ::_S_free_list[ 00539 __default_alloc_template<__threads, __inst>::_NFREELISTS 00540 ] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; 00541 // The 16 zeros are necessary to make version 4.1 of the SunPro 00542 // compiler happy. Otherwise it appears to allocate too little 00543 // space for the array. 00544 00545 #endif /* ! __USE_MALLOC */ 00546 00547 // This implements allocators as specified in the C++ standard. 00548 // 00549 // Note that standard-conforming allocators use many language features 00550 // that are not yet widely implemented. In particular, they rely on 00551 // member templates, partial specialization, partial ordering of function 00552 // templates, the typename keyword, and the use of the template keyword 00553 // to refer to a template member of a dependent type. 00554 00555 template <class _Tp> 00556 class allocator { 00557 typedef alloc _Alloc; // The underlying allocator. 00558 public: 00559 typedef size_t size_type; 00560 typedef ptrdiff_t difference_type; 00561 typedef _Tp* pointer; 00562 typedef const _Tp* const_pointer; 00563 typedef _Tp& reference; 00564 typedef const _Tp& const_reference; 00565 typedef _Tp value_type; 00566 00567 template <class _Tp1> struct rebind { 00568 typedef allocator<_Tp1> other; 00569 }; 00570 00571 allocator() __STL_NOTHROW {} 00572 allocator(const allocator&) __STL_NOTHROW {} 00573 template <class _Tp1> allocator(const allocator<_Tp1>&) __STL_NOTHROW {} 00574 ~allocator() __STL_NOTHROW {} 00575 00576 pointer address(reference __x) const { return &__x; } 00577 const_pointer address(const_reference __x) const { return &__x; } 00578 00579 // __n is permitted to be 0. The C++ standard says nothing about what 00580 // the return value is when __n == 0. 00581 _Tp* allocate(size_type __n, const void* = 0) { 00582 return __n != 0 ? static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp))) 00583 : 0; 00584 } 00585 00586 // __p is not permitted to be a null pointer. 00587 void deallocate(pointer __p, size_type __n) 00588 { _Alloc::deallocate(__p, __n * sizeof(_Tp)); } 00589 00590 size_type max_size() const __STL_NOTHROW 00591 { return size_t(-1) / sizeof(_Tp); } 00592 00593 void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); } 00594 void destroy(pointer __p) { __p->~_Tp(); } 00595 }; 00596 00597 template<> 00598 class allocator<void> { 00599 public: 00600 typedef size_t size_type; 00601 typedef ptrdiff_t difference_type; 00602 typedef void* pointer; 00603 typedef const void* const_pointer; 00604 typedef void value_type; 00605 00606 template <class _Tp1> struct rebind { 00607 typedef allocator<_Tp1> other; 00608 }; 00609 }; 00610 00611 00612 template <class _T1, class _T2> 00613 inline bool operator==(const allocator<_T1>&, const allocator<_T2>&) 00614 { 00615 return true; 00616 } 00617 00618 template <class _T1, class _T2> 00619 inline bool operator!=(const allocator<_T1>&, const allocator<_T2>&) 00620 { 00621 return false; 00622 } 00623 00624 // Allocator adaptor to turn an SGI-style allocator (e.g. alloc, malloc_alloc) 00625 // into a standard-conforming allocator. Note that this adaptor does 00626 // *not* assume that all objects of the underlying alloc class are 00627 // identical, nor does it assume that all of the underlying alloc's 00628 // member functions are static member functions. Note, also, that 00629 // __allocator<_Tp, alloc> is essentially the same thing as allocator<_Tp>. 00630 00631 template <class _Tp, class _Alloc> 00632 struct __allocator { 00633 _Alloc __underlying_alloc; 00634 00635 typedef size_t size_type; 00636 typedef ptrdiff_t difference_type; 00637 typedef _Tp* pointer; 00638 typedef const _Tp* const_pointer; 00639 typedef _Tp& reference; 00640 typedef const _Tp& const_reference; 00641 typedef _Tp value_type; 00642 00643 template <class _Tp1> struct rebind { 00644 typedef __allocator<_Tp1, _Alloc> other; 00645 }; 00646 00647 __allocator() __STL_NOTHROW {} 00648 __allocator(const __allocator& __a) __STL_NOTHROW 00649 : __underlying_alloc(__a.__underlying_alloc) {} 00650 template <class _Tp1> 00651 __allocator(const __allocator<_Tp1, _Alloc>& __a) __STL_NOTHROW 00652 : __underlying_alloc(__a.__underlying_alloc) {} 00653 ~__allocator() __STL_NOTHROW {} 00654 00655 pointer address(reference __x) const { return &__x; } 00656 const_pointer address(const_reference __x) const { return &__x; } 00657 00658 // __n is permitted to be 0. 00659 _Tp* allocate(size_type __n, const void* = 0) { 00660 return __n != 0 00661 ? static_cast<_Tp*>(__underlying_alloc.allocate(__n * sizeof(_Tp))) 00662 : 0; 00663 } 00664 00665 // __p is not permitted to be a null pointer. 00666 void deallocate(pointer __p, size_type __n) 00667 { __underlying_alloc.deallocate(__p, __n * sizeof(_Tp)); } 00668 00669 size_type max_size() const __STL_NOTHROW 00670 { return size_t(-1) / sizeof(_Tp); } 00671 00672 void construct(pointer __p, const _Tp& __val) { new(__p) _Tp(__val); } 00673 void destroy(pointer __p) { __p->~_Tp(); } 00674 }; 00675 00676 template <class _Alloc> 00677 class __allocator<void, _Alloc> { 00678 typedef size_t size_type; 00679 typedef ptrdiff_t difference_type; 00680 typedef void* pointer; 00681 typedef const void* const_pointer; 00682 typedef void value_type; 00683 00684 template <class _Tp1> struct rebind { 00685 typedef __allocator<_Tp1, _Alloc> other; 00686 }; 00687 }; 00688 00689 template <class _Tp, class _Alloc> 00690 inline bool operator==(const __allocator<_Tp, _Alloc>& __a1, 00691 const __allocator<_Tp, _Alloc>& __a2) 00692 { 00693 return __a1.__underlying_alloc == __a2.__underlying_alloc; 00694 } 00695 00696 template <class _Tp, class _Alloc> 00697 inline bool operator!=(const __allocator<_Tp, _Alloc>& __a1, 00698 const __allocator<_Tp, _Alloc>& __a2) 00699 { 00700 return __a1.__underlying_alloc != __a2.__underlying_alloc; 00701 } 00702 00703 // Comparison operators for all of the predifined SGI-style allocators. 00704 // This ensures that __allocator<malloc_alloc> (for example) will 00705 // work correctly. 00706 00707 template <int inst> 00708 inline bool operator==(const __malloc_alloc_template<inst>&, 00709 const __malloc_alloc_template<inst>&) 00710 { 00711 return true; 00712 } 00713 00714 template <int __inst> 00715 inline bool operator!=(const __malloc_alloc_template<__inst>&, 00716 const __malloc_alloc_template<__inst>&) 00717 { 00718 return false; 00719 } 00720 00721 template <class _Alloc> 00722 inline bool operator==(const debug_alloc<_Alloc>&, 00723 const debug_alloc<_Alloc>&) { 00724 return true; 00725 } 00726 00727 template <class _Alloc> 00728 inline bool operator!=(const debug_alloc<_Alloc>&, 00729 const debug_alloc<_Alloc>&) { 00730 return false; 00731 } 00732 00733 // Another allocator adaptor: _Alloc_traits. This serves two 00734 // purposes. First, make it possible to write containers that can use 00735 // either SGI-style allocators or standard-conforming allocator. 00736 // Second, provide a mechanism so that containers can query whether or 00737 // not the allocator has distinct instances. If not, the container 00738 // can avoid wasting a word of memory to store an empty object. 00739 00740 // This adaptor uses partial specialization. The general case of 00741 // _Alloc_traits<_Tp, _Alloc> assumes that _Alloc is a 00742 // standard-conforming allocator, possibly with non-equal instances 00743 // and non-static members. (It still behaves correctly even if _Alloc 00744 // has static member and if all instances are equal. Refinements 00745 // affect performance, not correctness.) 00746 00747 // There are always two members: allocator_type, which is a standard- 00748 // conforming allocator type for allocating objects of type _Tp, and 00749 // _S_instanceless, a static const member of type bool. If 00750 // _S_instanceless is true, this means that there is no difference 00751 // between any two instances of type allocator_type. Furthermore, if 00752 // _S_instanceless is true, then _Alloc_traits has one additional 00753 // member: _Alloc_type. This type encapsulates allocation and 00754 // deallocation of objects of type _Tp through a static interface; it 00755 // has two member functions, whose signatures are 00756 // static _Tp* allocate(size_t) 00757 // static void deallocate(_Tp*, size_t) 00758 00759 // The fully general version. 00760 00761 template <class _Tp, class _Allocator> 00762 struct _Alloc_traits 00763 { 00764 static const bool _S_instanceless = false; 00765 typedef typename _Allocator::template rebind<_Tp>::other allocator_type; 00766 }; 00767 00768 template <class _Tp, class _Allocator> 00769 const bool _Alloc_traits<_Tp, _Allocator>::_S_instanceless; 00770 00771 // The version for the default allocator. 00772 00773 template <class _Tp, class _Tp1> 00774 struct _Alloc_traits<_Tp, allocator<_Tp1> > 00775 { 00776 static const bool _S_instanceless = true; 00777 typedef simple_alloc<_Tp, alloc> _Alloc_type; 00778 typedef allocator<_Tp> allocator_type; 00779 }; 00780 00781 // Versions for the predefined SGI-style allocators. 00782 00783 template <class _Tp, int __inst> 00784 struct _Alloc_traits<_Tp, __malloc_alloc_template<__inst> > 00785 { 00786 static const bool _S_instanceless = true; 00787 typedef simple_alloc<_Tp, __malloc_alloc_template<__inst> > _Alloc_type; 00788 typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type; 00789 }; 00790 00791 #ifndef __USE_MALLOC 00792 template <class _Tp, bool __threads, int __inst> 00793 struct _Alloc_traits<_Tp, __default_alloc_template<__threads, __inst> > 00794 { 00795 static const bool _S_instanceless = true; 00796 typedef simple_alloc<_Tp, __default_alloc_template<__threads, __inst> > 00797 _Alloc_type; 00798 typedef __allocator<_Tp, __default_alloc_template<__threads, __inst> > 00799 allocator_type; 00800 }; 00801 #endif 00802 00803 template <class _Tp, class _Alloc> 00804 struct _Alloc_traits<_Tp, debug_alloc<_Alloc> > 00805 { 00806 static const bool _S_instanceless = true; 00807 typedef simple_alloc<_Tp, debug_alloc<_Alloc> > _Alloc_type; 00808 typedef __allocator<_Tp, debug_alloc<_Alloc> > allocator_type; 00809 }; 00810 00811 // Versions for the __allocator adaptor used with the predefined 00812 // SGI-style allocators. 00813 00814 template <class _Tp, class _Tp1, int __inst> 00815 struct _Alloc_traits<_Tp, 00816 __allocator<_Tp1, __malloc_alloc_template<__inst> > > 00817 { 00818 static const bool _S_instanceless = true; 00819 typedef simple_alloc<_Tp, __malloc_alloc_template<__inst> > _Alloc_type; 00820 typedef __allocator<_Tp, __malloc_alloc_template<__inst> > allocator_type; 00821 }; 00822 00823 #ifndef __USE_MALLOC 00824 template <class _Tp, class _Tp1, bool __thr, int __inst> 00825 struct _Alloc_traits<_Tp, 00826 __allocator<_Tp1, 00827 __default_alloc_template<__thr, __inst> > > 00828 { 00829 static const bool _S_instanceless = true; 00830 typedef simple_alloc<_Tp, __default_alloc_template<__thr,__inst> > 00831 _Alloc_type; 00832 typedef __allocator<_Tp, __default_alloc_template<__thr,__inst> > 00833 allocator_type; 00834 }; 00835 #endif 00836 00837 template <class _Tp, class _Tp1, class _Alloc> 00838 struct _Alloc_traits<_Tp, __allocator<_Tp1, debug_alloc<_Alloc> > > 00839 { 00840 static const bool _S_instanceless = true; 00841 typedef simple_alloc<_Tp, debug_alloc<_Alloc> > _Alloc_type; 00842 typedef __allocator<_Tp, debug_alloc<_Alloc> > allocator_type; 00843 }; 00844 00845 } // namespace std 00846 00847 #endif /* __SGI_STL_INTERNAL_ALLOC_H */ 00848 00849 // Local Variables: 00850 // mode:C++ 00851 // End: Generated on Mon Apr 8 03:11:37 2002 for libstdc++-v3 Source by ![]() |