// MT-optimized allocator -*- C++ -*-
-// Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+// Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
-// Free Software Foundation; either version 2, or (at your option)
+// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License along
-// with this library; see the file COPYING. If not, write to the Free
-// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
-// USA.
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
-// As a special exception, you may use this file as part of a free software
-// library without restriction. Specifically, if other files instantiate
-// templates or use macros or inline functions from this file, or you compile
-// this file and link it with other files to produce an executable, this
-// file does not by itself cause the resulting executable to be covered by
-// the GNU General Public License. This exception does not however
-// invalidate any other reasons why the executable file might be covered by
-// the GNU General Public License.
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
/** @file ext/mt_allocator.h
* This file is a GNU extension to the Standard C++ Library.
- * You should only include this header if you are using GCC 3 or later.
*/
#ifndef _MT_ALLOCATOR_H
#include <new>
#include <cstdlib>
#include <bits/functexcept.h>
-#include <bits/gthr.h>
-#include <bits/atomicity.h>
+#include <ext/atomicity.h>
+#include <bits/move.h>
-namespace __gnu_cxx
+namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
- /**
- * This is a fixed size (power of 2) allocator which - when
- * compiled with thread support - will maintain one freelist per
- * size per thread plus a "global" one. Steps are taken to limit
- * the per thread freelist sizes (by returning excess back to
- * "global").
- *
- * Further details:
- * http://gcc.gnu.org/onlinedocs/libstdc++/ext/mt_allocator.html
- */
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ using std::size_t;
+ using std::ptrdiff_t;
+
typedef void (*__destroy_handler)(void*);
- typedef void (*__create_handler)(void);
+ /// Base class for pool object.
struct __pool_base
{
// Using short int as type for the binmap implies we are never
- // caching blocks larger than 65535 with this allocator.
+ // caching blocks larger than 32768 with this allocator.
typedef unsigned short int _Binmap_type;
// Variables used to configure the behavior of the allocator,
// assigned and explained in detail below.
struct _Tune
- {
+ {
// Compile time constants for the default _Tune values.
enum { _S_align = 8 };
enum { _S_max_bytes = 128 };
// Allocation requests (after round-up to power of 2) below
// this value will be handled by the allocator. A raw new/
// call will be used for requests larger than this value.
+ // NB: Must be much smaller than _M_chunk_size and in any
+ // case <= 32768.
size_t _M_max_bytes;
-
+
// Size in bytes of the smallest bin.
- // NB: Must be a power of 2 and >= _M_align.
+ // NB: Must be a power of 2 and >= _M_align (and of course
+ // much smaller than _M_max_bytes).
size_t _M_min_bin;
-
+
// In order to avoid fragmenting and minimize the number of
// new() calls we always request new memory using this
// value. Based on previous discussions on the libstdc++
- // mailing list we have choosen the value below.
+ // mailing list we have chosen the value below.
// See http://gcc.gnu.org/ml/libstdc++/2001-07/msg00077.html
+ // NB: At least one order of magnitude > _M_max_bytes.
size_t _M_chunk_size;
-
+
// The maximum number of supported threads. For
// single-threaded operation, use one. Maximum values will
// vary depending on details of the underlying system. (For
// /proc/sys/kernel/threads-max, while Linux 2.6.6 reports
// 65534)
size_t _M_max_threads;
-
+
// Each time a deallocation occurs in a threaded application
// we make sure that there are no more than
// _M_freelist_headroom % of used memory on the freelist. If
: _M_align(_S_align), _M_max_bytes(_S_max_bytes), _M_min_bin(_S_min_bin),
_M_chunk_size(_S_chunk_size), _M_max_threads(_S_max_threads),
_M_freelist_headroom(_S_freelist_headroom),
- _M_force_new(getenv("GLIBCXX_FORCE_NEW") ? true : false)
+ _M_force_new(std::getenv("GLIBCXX_FORCE_NEW") ? true : false)
{ }
explicit
_M_chunk_size(__chunk), _M_max_threads(__maxthreads),
_M_freelist_headroom(__headroom), _M_force_new(__force)
{ }
-
- bool
- is_default() const
- {
- bool __ret = true;
- __ret &= _M_align == _S_align;
- __ret &= _M_max_bytes == _S_max_bytes;
- __ret &= _M_min_bin == _S_min_bin;
- __ret &= _M_chunk_size == _S_chunk_size;
- __ret &= _M_max_threads == _S_max_threads;
- __ret &= _M_freelist_headroom == _S_freelist_headroom;
- return __ret;
- }
};
struct _Block_address
_M_get_binmap(size_t __bytes)
{ return _M_binmap[__bytes]; }
- explicit __pool_base()
- : _M_options(_Tune()), _M_binmap(NULL), _M_init(false) { }
+ size_t
+ _M_get_align()
+ { return _M_options._M_align; }
+
+ explicit
+ __pool_base()
+ : _M_options(_Tune()), _M_binmap(0), _M_init(false) { }
+
+ explicit
+ __pool_base(const _Tune& __options)
+ : _M_options(__options), _M_binmap(0), _M_init(false) { }
- explicit __pool_base(const _Tune& __tune)
- : _M_options(__tune), _M_binmap(NULL), _M_init(false) { }
+ private:
+ explicit
+ __pool_base(const __pool_base&);
+
+ __pool_base&
+ operator=(const __pool_base&);
protected:
// Configuration options.
_Binmap_type* _M_binmap;
- // We need to create the initial lists and set up some variables
- // before we can answer to the first request for memory.
+ // Configuration of the pool object via _M_options can happen
+ // after construction but before initialization. After
+ // initialization is complete, this variable is set to true.
bool _M_init;
};
- // Data describing the underlying memory pool, parameterized on
- // threading support.
+
+ /**
+ * @brief Data describing the underlying memory pool, parameterized on
+ * threading support.
+ */
template<bool _Thread>
class __pool;
+ /// Specialization for single thread.
template<>
- class __pool<true>;
+ class __pool<false> : public __pool_base
+ {
+ public:
+ union _Block_record
+ {
+ // Points to the block_record of the next free block.
+ _Block_record* _M_next;
+ };
- template<>
- class __pool<false>;
+ struct _Bin_record
+ {
+ // An "array" of pointers to the first free block.
+ _Block_record** _M_first;
+
+ // A list of the initial addresses of all allocated blocks.
+ _Block_address* _M_address;
+ };
+
+ void
+ _M_initialize_once()
+ {
+ if (__builtin_expect(_M_init == false, false))
+ _M_initialize();
+ }
+
+ void
+ _M_destroy() throw();
+
+ char*
+ _M_reserve_block(size_t __bytes, const size_t __thread_id);
+
+ void
+ _M_reclaim_block(char* __p, size_t __bytes) throw ();
+
+ size_t
+ _M_get_thread_id() { return 0; }
+
+ const _Bin_record&
+ _M_get_bin(size_t __which)
+ { return _M_bin[__which]; }
+
+ void
+ _M_adjust_freelist(const _Bin_record&, _Block_record*, size_t)
+ { }
+
+ explicit __pool()
+ : _M_bin(0), _M_bin_size(1) { }
+ explicit __pool(const __pool_base::_Tune& __tune)
+ : __pool_base(__tune), _M_bin(0), _M_bin_size(1) { }
+
+ private:
+ // An "array" of bin_records each of which represents a specific
+ // power of 2 size. Memory to this "array" is allocated in
+ // _M_initialize().
+ _Bin_record* _M_bin;
+
+ // Actual value calculated in _M_initialize().
+ size_t _M_bin_size;
+ void
+ _M_initialize();
+ };
+
#ifdef __GTHREADS
- // Specialization for thread enabled, via gthreads.h.
+ /// Specialization for thread enabled, via gthreads.h.
template<>
class __pool<true> : public __pool_base
{
struct _Thread_record
{
// Points to next free thread id record. NULL if last record in list.
- _Thread_record* volatile _M_next;
+ _Thread_record* _M_next;
// Thread id ranging from 1 to _S_max_threads.
size_t _M_id;
union _Block_record
{
// Points to the block_record of the next free block.
- _Block_record* volatile _M_next;
+ _Block_record* _M_next;
// The thread id of the thread which has requested this block.
size_t _M_thread_id;
// An "array" of pointers to the first free block for each
// thread id. Memory to this "array" is allocated in
// _S_initialize() for _S_max_threads + global pool 0.
- _Block_record** volatile _M_first;
+ _Block_record** _M_first;
// A list of the initial addresses of all allocated blocks.
_Block_address* _M_address;
// An "array" of counters used to keep track of the amount of
// blocks that are on the freelist/used for each thread id.
- // Memory to these "arrays" is allocated in _S_initialize() for
- // _S_max_threads + global pool 0.
- size_t* volatile _M_free;
- size_t* volatile _M_used;
+ // - Note that the second part of the allocated _M_used "array"
+ // actually hosts (atomic) counters of reclaimed blocks: in
+ // _M_reserve_block and in _M_reclaim_block those numbers are
+ // subtracted from the first ones to obtain the actual size
+ // of the "working set" of the given thread.
+ // - Memory to these "arrays" is allocated in _S_initialize()
+ // for _S_max_threads + global pool 0.
+ size_t* _M_free;
+ size_t* _M_used;
// Each bin has its own mutex which is used to ensure data
// integrity while changing "ownership" on a block. The mutex
__gthread_mutex_t* _M_mutex;
};
+ // XXX GLIBCXX_ABI Deprecated
void
- _M_initialize(__destroy_handler __d);
+ _M_initialize(__destroy_handler);
void
- _M_initialize_once(__create_handler __c)
+ _M_initialize_once()
{
- // Although the test in __gthread_once() would suffice, we
- // wrap test of the once condition in our own unlocked
- // check. This saves one function call to pthread_once()
- // (which itself only tests for the once value unlocked anyway
- // and immediately returns if set)
if (__builtin_expect(_M_init == false, false))
- {
- if (__gthread_active_p())
- __gthread_once(&_M_once, __c);
- if (!_M_init)
- __c();
- }
+ _M_initialize();
}
void
_M_reserve_block(size_t __bytes, const size_t __thread_id);
void
- _M_reclaim_block(char* __p, size_t __bytes);
+ _M_reclaim_block(char* __p, size_t __bytes) throw ();
const _Bin_record&
_M_get_bin(size_t __which)
}
}
- void
- _M_destroy_thread_key(void* __freelist_pos);
+ // XXX GLIBCXX_ABI Deprecated
+ _GLIBCXX_CONST void
+ _M_destroy_thread_key(void*) throw ();
size_t
_M_get_thread_id();
explicit __pool()
- : _M_bin(NULL), _M_bin_size(1), _M_thread_freelist(NULL)
- {
- // On some platforms, __gthread_once_t is an aggregate.
- __gthread_once_t __tmp = __GTHREAD_ONCE_INIT;
- _M_once = __tmp;
- }
+ : _M_bin(0), _M_bin_size(1), _M_thread_freelist(0)
+ { }
explicit __pool(const __pool_base::_Tune& __tune)
- : __pool_base(__tune), _M_bin(NULL), _M_bin_size(1),
- _M_thread_freelist(NULL)
- {
- // On some platforms, __gthread_once_t is an aggregate.
- __gthread_once_t __tmp = __GTHREAD_ONCE_INIT;
- _M_once = __tmp;
- }
-
- ~__pool() { }
+ : __pool_base(__tune), _M_bin(0), _M_bin_size(1),
+ _M_thread_freelist(0)
+ { }
private:
// An "array" of bin_records each of which represents a specific
// power of 2 size. Memory to this "array" is allocated in
// _M_initialize().
- _Bin_record* volatile _M_bin;
+ _Bin_record* _M_bin;
// Actual value calculated in _M_initialize().
size_t _M_bin_size;
- __gthread_once_t _M_once;
-
_Thread_record* _M_thread_freelist;
void* _M_thread_freelist_initial;
- };
-#endif
-
- // Specialization for single thread.
- template<>
- class __pool<false> : public __pool_base
- {
- public:
- union _Block_record
- {
- // Points to the block_record of the next free block.
- _Block_record* volatile _M_next;
- };
-
- struct _Bin_record
- {
- // An "array" of pointers to the first free block.
- _Block_record** volatile _M_first;
-
- // A list of the initial addresses of all allocated blocks.
- _Block_address* _M_address;
- };
-
- void
- _M_initialize_once()
- {
- if (__builtin_expect(_M_init == false, false))
- _M_initialize();
- }
-
- void
- _M_destroy() throw();
-
- char*
- _M_reserve_block(size_t __bytes, const size_t __thread_id);
-
- void
- _M_reclaim_block(char* __p, size_t __bytes);
-
- size_t
- _M_get_thread_id() { return 0; }
-
- const _Bin_record&
- _M_get_bin(size_t __which)
- { return _M_bin[__which]; }
-
- void
- _M_adjust_freelist(const _Bin_record&, _Block_record*, size_t)
- { }
-
- explicit __pool()
- : _M_bin(NULL), _M_bin_size(1) { }
-
- explicit __pool(const __pool_base::_Tune& __tune)
- : __pool_base(__tune), _M_bin(NULL), _M_bin_size(1) { }
-
- ~__pool() { }
-
- private:
- // An "array" of bin_records each of which represents a specific
- // power of 2 size. Memory to this "array" is allocated in
- // _M_initialize().
- _Bin_record* volatile _M_bin;
-
- // Actual value calculated in _M_initialize().
- size_t _M_bin_size;
void
_M_initialize();
- };
+ };
+#endif
- template<bool _Thread>
- struct __common_pool_policy
+ template<template <bool> class _PoolTp, bool _Thread>
+ struct __common_pool
{
- typedef __pool<_Thread> __pool_type;
-
- template<typename _Tp1, bool _Thread1 = _Thread>
- struct _M_rebind;
-
- template<typename _Tp1>
- struct _M_rebind<_Tp1, true>
- { typedef __common_pool_policy<true> other; };
-
- template<typename _Tp1>
- struct _M_rebind<_Tp1, false>
- { typedef __common_pool_policy<false> other; };
-
- static __pool_type&
+ typedef _PoolTp<_Thread> pool_type;
+
+ static pool_type&
_S_get_pool()
{
- static __pool_type _S_pool;
+ static pool_type _S_pool;
return _S_pool;
}
+ };
+
+ template<template <bool> class _PoolTp, bool _Thread>
+ struct __common_pool_base;
+
+ template<template <bool> class _PoolTp>
+ struct __common_pool_base<_PoolTp, false>
+ : public __common_pool<_PoolTp, false>
+ {
+ using __common_pool<_PoolTp, false>::_S_get_pool;
static void
- _S_initialize_once()
- {
+ _S_initialize_once()
+ {
static bool __init;
if (__builtin_expect(__init == false, false))
{
}
};
- template<>
- struct __common_pool_policy<true>;
-
#ifdef __GTHREADS
- template<>
- struct __common_pool_policy<true>
+ template<template <bool> class _PoolTp>
+ struct __common_pool_base<_PoolTp, true>
+ : public __common_pool<_PoolTp, true>
{
- typedef __pool<true> __pool_type;
-
- template<typename _Tp1, bool _Thread1 = true>
- struct _M_rebind;
-
- template<typename _Tp1>
- struct _M_rebind<_Tp1, true>
- { typedef __common_pool_policy<true> other; };
-
- template<typename _Tp1>
- struct _M_rebind<_Tp1, false>
- { typedef __common_pool_policy<false> other; };
-
- static __pool_type&
- _S_get_pool()
- {
- static __pool_type _S_pool;
- return _S_pool;
- }
-
- static void
- _S_destroy_thread_key(void* __freelist_pos)
- { _S_get_pool()._M_destroy_thread_key(__freelist_pos); }
+ using __common_pool<_PoolTp, true>::_S_get_pool;
static void
_S_initialize()
- { _S_get_pool()._M_initialize(_S_destroy_thread_key); }
+ { _S_get_pool()._M_initialize_once(); }
static void
- _S_initialize_once()
+ _S_initialize_once()
{
static bool __init;
if (__builtin_expect(__init == false, false))
{
- _S_get_pool()._M_initialize_once(_S_initialize);
+ if (__gthread_active_p())
+ {
+ // On some platforms, __gthread_once_t is an aggregate.
+ static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
+ __gthread_once(&__once, _S_initialize);
+ }
+
+ // Double check initialization. May be necessary on some
+ // systems for proper construction when not compiling with
+ // thread flags.
+ _S_get_pool()._M_initialize_once();
__init = true;
}
}
- };
+ };
#endif
-
- template<typename _Tp, bool _Thread>
- struct __per_type_pool_policy
+ /// Policy for shared __pool objects.
+ template<template <bool> class _PoolTp, bool _Thread>
+ struct __common_pool_policy : public __common_pool_base<_PoolTp, _Thread>
{
- typedef __pool<_Thread> __pool_type;
-
- template<typename _Tp1, bool _Thread1 = _Thread>
- struct _M_rebind;
+ template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
+ bool _Thread1 = _Thread>
+ struct _M_rebind
+ { typedef __common_pool_policy<_PoolTp1, _Thread1> other; };
- template<typename _Tp1>
- struct _M_rebind<_Tp1, false>
- { typedef __per_type_pool_policy<_Tp1, false> other; };
-
- template<typename _Tp1>
- struct _M_rebind<_Tp1, true>
- { typedef __per_type_pool_policy<_Tp1, true> other; };
+ using __common_pool_base<_PoolTp, _Thread>::_S_get_pool;
+ using __common_pool_base<_PoolTp, _Thread>::_S_initialize_once;
+ };
+
- // Avoid static initialization ordering issues.
- static __pool_type&
- _S_get_pool()
+ template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
+ struct __per_type_pool
+ {
+ typedef _Tp value_type;
+ typedef _PoolTp<_Thread> pool_type;
+
+ static pool_type&
+ _S_get_pool()
{
- // Sane defaults for the __pool_type.
- const static size_t __align = __alignof__(_Tp) >= sizeof(typename __pool_type::_Block_record) ? __alignof__(_Tp) : sizeof(typename __pool_type::_Block_record);
- static __pool_base::_Tune _S_tune(__align, sizeof(_Tp) * 128, (sizeof(_Tp) * 2) >= __align ? sizeof(_Tp) * 2 : __align, __pool_type::_Tune::_S_chunk_size, __pool_type::_Tune::_S_max_threads, __pool_type::_Tune::_S_freelist_headroom, getenv("GLIBCXX_FORCE_NEW") ? true : false);
- static __pool_type _S_pool(_S_tune);
+ // Sane defaults for the _PoolTp.
+ typedef typename pool_type::_Block_record _Block_record;
+ const static size_t __a = (__alignof__(_Tp) >= sizeof(_Block_record)
+ ? __alignof__(_Tp) : sizeof(_Block_record));
+
+ typedef typename __pool_base::_Tune _Tune;
+ static _Tune _S_tune(__a, sizeof(_Tp) * 64,
+ sizeof(_Tp) * 2 >= __a ? sizeof(_Tp) * 2 : __a,
+ sizeof(_Tp) * size_t(_Tune::_S_chunk_size),
+ _Tune::_S_max_threads,
+ _Tune::_S_freelist_headroom,
+ std::getenv("GLIBCXX_FORCE_NEW") ? true : false);
+ static pool_type _S_pool(_S_tune);
return _S_pool;
}
+ };
+
+ template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
+ struct __per_type_pool_base;
+
+ template<typename _Tp, template <bool> class _PoolTp>
+ struct __per_type_pool_base<_Tp, _PoolTp, false>
+ : public __per_type_pool<_Tp, _PoolTp, false>
+ {
+ using __per_type_pool<_Tp, _PoolTp, false>::_S_get_pool;
static void
- _S_initialize_once()
- {
+ _S_initialize_once()
+ {
static bool __init;
if (__builtin_expect(__init == false, false))
{
}
};
- template<typename _Tp>
- struct __per_type_pool_policy<_Tp, true>;
-
-#ifdef __GTHREADS
- template<typename _Tp>
- struct __per_type_pool_policy<_Tp, true>
+ #ifdef __GTHREADS
+ template<typename _Tp, template <bool> class _PoolTp>
+ struct __per_type_pool_base<_Tp, _PoolTp, true>
+ : public __per_type_pool<_Tp, _PoolTp, true>
{
- typedef __pool<true> __pool_type;
-
- template<typename _Tp1, bool _Thread1 = true>
- struct _M_rebind;
-
- template<typename _Tp1>
- struct _M_rebind<_Tp1, false>
- { typedef __per_type_pool_policy<_Tp1, false> other; };
+ using __per_type_pool<_Tp, _PoolTp, true>::_S_get_pool;
- template<typename _Tp1>
- struct _M_rebind<_Tp1, true>
- { typedef __per_type_pool_policy<_Tp1, true> other; };
-
- // Avoid static initialization ordering issues.
- static __pool_type&
- _S_get_pool( )
- {
- // Sane defaults for the __pool_type.
- const static size_t __align = __alignof__(_Tp) >= sizeof(typename __pool_type::_Block_record) ? __alignof__(_Tp) : sizeof(typename __pool_type::_Block_record);
- static __pool_base::_Tune _S_tune(__align, sizeof(_Tp) * 128, (sizeof(_Tp) * 2) >= __align ? sizeof(_Tp) * 2 : __align, __pool_type::_Tune::_S_chunk_size, __pool_type::_Tune::_S_max_threads, __pool_type::_Tune::_S_freelist_headroom, getenv("GLIBCXX_FORCE_NEW") ? true : false);
- static __pool_type _S_pool(_S_tune);
- return _S_pool;
- }
-
- static void
- _S_destroy_thread_key(void* __freelist_pos)
- { _S_get_pool()._M_destroy_thread_key(__freelist_pos); }
-
static void
_S_initialize()
- { _S_get_pool()._M_initialize(_S_destroy_thread_key); }
+ { _S_get_pool()._M_initialize_once(); }
static void
- _S_initialize_once()
+ _S_initialize_once()
{
static bool __init;
if (__builtin_expect(__init == false, false))
{
- _S_get_pool()._M_initialize_once(_S_initialize);
+ if (__gthread_active_p())
+ {
+ // On some platforms, __gthread_once_t is an aggregate.
+ static __gthread_once_t __once = __GTHREAD_ONCE_INIT;
+ __gthread_once(&__once, _S_initialize);
+ }
+
+ // Double check initialization. May be necessary on some
+ // systems for proper construction when not compiling with
+ // thread flags.
+ _S_get_pool()._M_initialize_once();
__init = true;
}
}
};
#endif
+ /// Policy for individual __pool objects.
+ template<typename _Tp, template <bool> class _PoolTp, bool _Thread>
+ struct __per_type_pool_policy
+ : public __per_type_pool_base<_Tp, _PoolTp, _Thread>
+ {
+ template<typename _Tp1, template <bool> class _PoolTp1 = _PoolTp,
+ bool _Thread1 = _Thread>
+ struct _M_rebind
+ { typedef __per_type_pool_policy<_Tp1, _PoolTp1, _Thread1> other; };
+
+ using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_get_pool;
+ using __per_type_pool_base<_Tp, _PoolTp, _Thread>::_S_initialize_once;
+ };
+
+
+ /// Base class for _Tp dependent member functions.
template<typename _Tp>
class __mt_alloc_base
{
pointer
address(reference __x) const
- { return &__x; }
+ { return std::__addressof(__x); }
const_pointer
address(const_reference __x) const
- { return &__x; }
+ { return std::__addressof(__x); }
size_type
max_size() const throw()
// 402. wrong new expression in [some_] allocator::construct
void
construct(pointer __p, const _Tp& __val)
- { ::new(__p) _Tp(__val); }
+ { ::new((void *)__p) _Tp(__val); }
+
+#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ template<typename... _Args>
+ void
+ construct(pointer __p, _Args&&... __args)
+ { ::new((void *)__p) _Tp(std::forward<_Args>(__args)...); }
+#endif
void
destroy(pointer __p) { __p->~_Tp(); }
};
#ifdef __GTHREADS
-#define __default_policy __common_pool_policy<true>
+#define __thread_default true
#else
-#define __default_policy __common_pool_policy<false>
+#define __thread_default false
#endif
- template<typename _Tp, typename _Poolp = __default_policy>
- class __mt_alloc : public __mt_alloc_base<_Tp>, _Poolp
+ /**
+ * @brief This is a fixed size (power of 2) allocator which - when
+ * compiled with thread support - will maintain one freelist per
+ * size per thread plus a @a global one. Steps are taken to limit
+ * the per thread freelist sizes (by returning excess back to
+ * the @a global list).
+ * @ingroup allocators
+ *
+ * Further details:
+ * http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt12ch32.html
+ */
+ template<typename _Tp,
+ typename _Poolp = __common_pool_policy<__pool, __thread_default> >
+ class __mt_alloc : public __mt_alloc_base<_Tp>
{
public:
typedef size_t size_type;
typedef _Tp& reference;
typedef const _Tp& const_reference;
typedef _Tp value_type;
- typedef _Poolp __policy_type;
- typedef typename _Poolp::__pool_type __pool_type;
+ typedef _Poolp __policy_type;
+ typedef typename _Poolp::pool_type __pool_type;
template<typename _Tp1, typename _Poolp1 = _Poolp>
struct rebind
typedef __mt_alloc<_Tp1, pol_type> other;
};
- __mt_alloc() throw()
- { __policy_type::_S_get_pool(); }
+ __mt_alloc() throw() { }
- __mt_alloc(const __mt_alloc&) throw()
- { __policy_type::_S_get_pool(); }
+ __mt_alloc(const __mt_alloc&) throw() { }
template<typename _Tp1, typename _Poolp1>
- __mt_alloc(const __mt_alloc<_Tp1, _Poolp1>& obj) throw()
- { __policy_type::_S_get_pool(); }
+ __mt_alloc(const __mt_alloc<_Tp1, _Poolp1>&) throw() { }
~__mt_alloc() throw() { }
_M_get_options()
{
// Return a copy, not a reference, for external consumption.
- return __pool_base::_Tune(this->_S_get_pool()._M_get_options());
+ return __policy_type::_S_get_pool()._M_get_options();
}
void
_M_set_options(__pool_base::_Tune __t)
- { this->_S_get_pool()._M_set_options(__t); }
+ { __policy_type::_S_get_pool()._M_set_options(__t); }
};
template<typename _Tp, typename _Poolp>
__mt_alloc<_Tp, _Poolp>::
allocate(size_type __n, const void*)
{
- this->_S_initialize_once();
+ if (__n > this->max_size())
+ std::__throw_bad_alloc();
+
+ __policy_type::_S_initialize_once();
// Requests larger than _M_max_bytes are handled by operator
// new/delete directly.
- __pool_type& __pool = this->_S_get_pool();
+ __pool_type& __pool = __policy_type::_S_get_pool();
const size_t __bytes = __n * sizeof(_Tp);
if (__pool._M_check_threshold(__bytes))
{
void* __ret = ::operator new(__bytes);
return static_cast<_Tp*>(__ret);
}
-
+
// Round up to power of 2 and figure out which bin to use.
const size_t __which = __pool._M_get_binmap(__bytes);
const size_t __thread_id = __pool._M_get_thread_id();
__bin._M_first[__thread_id] = __block->_M_next;
__pool._M_adjust_freelist(__bin, __block, __thread_id);
- const __pool_base::_Tune& __options = __pool._M_get_options();
- __c = reinterpret_cast<char*>(__block) + __options._M_align;
+ __c = reinterpret_cast<char*>(__block) + __pool._M_get_align();
}
else
{
__mt_alloc<_Tp, _Poolp>::
deallocate(pointer __p, size_type __n)
{
- // Requests larger than _M_max_bytes are handled by operators
- // new/delete directly.
- __pool_type& __pool = this->_S_get_pool();
- const size_t __bytes = __n * sizeof(_Tp);
- if (__pool._M_check_threshold(__bytes))
- ::operator delete(__p);
- else
- __pool._M_reclaim_block(reinterpret_cast<char*>(__p), __bytes);
+ if (__builtin_expect(__p != 0, true))
+ {
+ // Requests larger than _M_max_bytes are handled by
+ // operators new/delete directly.
+ __pool_type& __pool = __policy_type::_S_get_pool();
+ const size_t __bytes = __n * sizeof(_Tp);
+ if (__pool._M_check_threshold(__bytes))
+ ::operator delete(__p);
+ else
+ __pool._M_reclaim_block(reinterpret_cast<char*>(__p), __bytes);
+ }
}
template<typename _Tp, typename _Poolp>
operator!=(const __mt_alloc<_Tp, _Poolp>&, const __mt_alloc<_Tp, _Poolp>&)
{ return false; }
-#undef __default_policy
-} // namespace __gnu_cxx
+#undef __thread_default
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
#endif