demangle.h: Fix allocator type correctness, i.e.

* include/bits/demangle.h: Fix allocator type correctness,
	i.e. make sure that when we instantiate a container with a value
	type and an allocator, the allocator's value type matches the
	container's.
	* include/bits/stl_deque.h (_Deque_alloc_base): Eliminate.
	(_Deque_base): inherit directly from the deque's allocator.  Use
	rebinding instead of _Alloc_traits.  Pick up data members from
	_Deque_alloc_base.
	* include/bits/stl_list.h (_List_alloc_base): Eliminate.
	(_List_base): Inherit directly from the list's allocator.  Use
	rebinding instead of _Alloc_traits.  Pick up data members from
	_List_alloc_base.
	* include/bits/stl_vector.h (_Vector_alloc_base): Eliminate
	(_Vector_base): Inherit directly from the vector's allocator.  Use
	rebinding instead of _Alloc_traits.  Pick up data members from
	_Vector_alloc_base.
	* include/ext/hashtable.h: Fix allocator type correctness (the
	vector of buckets must be passed an allocator for objects of
	type _Node*).  Use rebinding instead of _Alloc_traits.

From-SVN: r74787
This commit is contained in:
Matt Austern 2003-12-18 18:35:38 +00:00 committed by Matt Austern
parent 38700ceee7
commit 8a1d8dd9c8
6 changed files with 140 additions and 291 deletions

View File

@ -1,3 +1,25 @@
2003-12-18 Matt Austern <austern@apple.com>
* include/bits/demangle.h: Fix allocator type correctness,
i.e. make sure that when we instantiate a container with a value
type and an allocator, the allocator's value type matches the
container's.
* include/bits/stl_deque.h (_Deque_alloc_base): Eliminate.
(_Deque_base): inherit directly from the deque's allocator. Use
rebinding instead of _Alloc_traits. Pick up data members from
_Deque_alloc_base.
* include/bits/stl_list.h (_List_alloc_base): Eliminate.
(_List_base): Inherit directly from the list's allocator. Use
rebinding instead of _Alloc_traits. Pick up data members from
_List_alloc_base.
* include/bits/stl_vector.h (_Vector_alloc_base): Eliminate
(_Vector_base): Inherit directly from the vector's allocator. Use
rebinding instead of _Alloc_traits. Pick up data members from
_Vector_alloc_base.
* include/ext/hashtable.h: Fix allocator type correctness (the
vector of buckets must be passed an allocator for objects of
type _Node*). Use rebinding instead of _Alloc_traits.
2003-12-17 Paolo Carlini <pcarlini@suse.de>
* include/bits/locale_facets.tcc (time_get::_M_extract_via_format):

View File

@ -113,7 +113,9 @@ namespace __gnu_cxx
template<typename Allocator>
class qualifier
{
typedef std::basic_string<char, std::char_traits<char>, Allocator>
typedef typename Allocator::template rebind<char>::other
char_Allocator;
typedef std::basic_string<char, std::char_traits<char>, char_Allocator>
string_type;
private:
@ -206,17 +208,22 @@ namespace __gnu_cxx
template<typename Allocator>
class qualifier_list
{
typedef std::basic_string<char, std::char_traits<char>, Allocator>
typedef typename Allocator::template rebind<char>::other
char_Allocator;
typedef std::basic_string<char, std::char_traits<char>, char_Allocator>
string_type;
private:
mutable bool M_printing_suppressed;
std::vector<qualifier<Allocator>, Allocator> M_qualifier_starts;
typedef qualifier<Allocator> qual;
typedef typename Allocator::template rebind<qual>::other qual_Allocator;
typedef std::vector<qual, qual_Allocator> qual_vector;
qual_vector M_qualifier_starts;
session<Allocator>& M_demangler;
void decode_KVrA(string_type& prefix, string_type& postfix, int cvq,
typename std::vector<qualifier<Allocator>, Allocator>::
const_reverse_iterator const& iter_array) const;
typename qual_vector::
const_reverse_iterator const& iter_array) const;
public:
qualifier_list(session<Allocator>& demangler_obj)
@ -270,7 +277,7 @@ namespace __gnu_cxx
#if _GLIBCXX_DEMANGLER_CWDEBUG
friend std::ostream& operator<<(std::ostream& os, qualifier_list const& list)
{
typename std::vector<qualifier<Allocator>, Allocator>::const_iterator
typename qual_vector::const_iterator
iter = list.M_qualifier_starts.begin();
if (iter != list.M_qualifier_starts.end())
{
@ -344,7 +351,9 @@ namespace __gnu_cxx
class session
{
friend class qualifier_list<Allocator>;
typedef std::basic_string<char, std::char_traits<char>, Allocator>
typedef typename Allocator::template rebind<char>::other
char_Allocator;
typedef std::basic_string<char, std::char_traits<char>, char_Allocator>
string_type;
private:
@ -361,9 +370,13 @@ namespace __gnu_cxx
bool M_name_is_conversion_operator;
bool M_template_args_need_space;
string_type M_function_name;
std::vector<int, Allocator> M_template_arg_pos;
typedef typename Allocator::template rebind<int>::other
int_Allocator;
typedef typename Allocator::template rebind<substitution_st>::other
subst_Allocator;
std::vector<int, int_Allocator> M_template_arg_pos;
int M_template_arg_pos_offset;
std::vector<substitution_st, Allocator> M_substitutions_pos;
std::vector<substitution_st, subst_Allocator> M_substitutions_pos;
implementation_details const& M_implementation_details;
#if _GLIBCXX_DEMANGLER_CWDEBUG
bool M_inside_add_substitution;
@ -1690,8 +1703,7 @@ namespace __gnu_cxx
void
qualifier_list<Allocator>::decode_KVrA(
string_type& prefix, string_type& postfix, int cvq,
typename std::vector<qualifier<Allocator>, Allocator>::
const_reverse_iterator const& iter_array) const
typename qual_vector::const_reverse_iterator const& iter_array) const
{
_GLIBCXX_DEMANGLER_DOUT_ENTERING3("decode_KVrA");
if ((cvq & cvq_K))
@ -1703,7 +1715,7 @@ namespace __gnu_cxx
if ((cvq & cvq_A))
{
int n = cvq >> 5;
for (typename std::vector<qualifier<Allocator>, Allocator>::
for (typename qual_vector::
const_reverse_iterator iter = iter_array;
iter != M_qualifier_starts.rend(); ++iter)
{
@ -1744,9 +1756,8 @@ namespace __gnu_cxx
{
_GLIBCXX_DEMANGLER_DOUT_ENTERING3("decode_qualifiers");
int cvq = 0;
typename std::vector<qualifier<Allocator>, Allocator>::
const_reverse_iterator iter_array;
for(typename std::vector<qualifier<Allocator>, Allocator>::
typename qual_vector::const_reverse_iterator iter_array;
for(typename qual_vector::
const_reverse_iterator iter = M_qualifier_starts.rbegin();
iter != M_qualifier_starts.rend(); ++iter)
{
@ -2676,8 +2687,8 @@ namespace __gnu_cxx
template<typename Allocator>
struct demangle
{
typedef Allocator allocator_type;
typedef std::basic_string<char, std::char_traits<char>, Allocator>
typedef typename Allocator::template rebind<char>::other char_Allocator;
typedef std::basic_string<char, std::char_traits<char>, char_Allocator>
string_type;
static string_type symbol(char const* in,
demangler::implementation_details const& id);
@ -2690,7 +2701,7 @@ namespace __gnu_cxx
// Demangle `input' which should be a mangled function name as for
// instance returned by nm(1).
template<typename Allocator>
std::basic_string<char, std::char_traits<char>, Allocator>
typename demangle<Allocator>::string_type
demangle<Allocator>::symbol(char const* input,
demangler::implementation_details const& id)
{
@ -2741,7 +2752,7 @@ namespace __gnu_cxx
// Demangle `input' which must be a zero terminated mangled type
// name as for instance returned by std::type_info::name().
template<typename Allocator>
std::basic_string<char, std::char_traits<char>, Allocator>
typename demangle<Allocator>::string_type
demangle<Allocator>::type(char const* input,
demangler::implementation_details const& id)
{

View File

@ -332,107 +332,12 @@ namespace __gnu_norm
return __x + __n;
}
/// @if maint Primary default version. @endif
/**
* @if maint
* Deque base class. It has two purposes. First, its constructor
* and destructor allocate (but don't initialize) storage. This makes
* %exception safety easier. Second, the base class encapsulates all of
* the differences between SGI-style allocators and standard-conforming
* allocators. (See allocator.h for more on this topic.) There are two
* versions: this ordinary one, and the space-saving specialization for
* instanceless allocators.
* @endif
*/
template<typename _Tp, typename _Alloc, bool __is_static>
class _Deque_alloc_base
{
public:
typedef typename _Alloc_traits<_Tp,_Alloc>::allocator_type allocator_type;
allocator_type get_allocator() const { return _M_node_allocator; }
_Deque_alloc_base(const allocator_type& __a)
: _M_node_allocator(__a), _M_map_allocator(__a),
_M_map(0), _M_map_size(0)
{}
protected:
typedef typename _Alloc_traits<_Tp*, _Alloc>::allocator_type
_Map_allocator_type;
_Tp*
_M_allocate_node()
{
return _M_node_allocator.allocate(__deque_buf_size(sizeof(_Tp)));
}
void
_M_deallocate_node(_Tp* __p)
{
_M_node_allocator.deallocate(__p, __deque_buf_size(sizeof(_Tp)));
}
_Tp**
_M_allocate_map(size_t __n)
{ return _M_map_allocator.allocate(__n); }
void
_M_deallocate_map(_Tp** __p, size_t __n)
{ _M_map_allocator.deallocate(__p, __n); }
allocator_type _M_node_allocator;
_Map_allocator_type _M_map_allocator;
_Tp** _M_map;
size_t _M_map_size;
};
/// @if maint Specialization for instanceless allocators. @endif
template<typename _Tp, typename _Alloc>
class _Deque_alloc_base<_Tp, _Alloc, true>
{
public:
typedef typename _Alloc_traits<_Tp,_Alloc>::allocator_type allocator_type;
allocator_type get_allocator() const { return allocator_type(); }
_Deque_alloc_base(const allocator_type&)
: _M_map(0), _M_map_size(0)
{}
protected:
typedef typename _Alloc_traits<_Tp,_Alloc>::_Alloc_type _Node_alloc_type;
typedef typename _Alloc_traits<_Tp*,_Alloc>::_Alloc_type _Map_alloc_type;
_Tp*
_M_allocate_node()
{
return _Node_alloc_type::allocate(__deque_buf_size(sizeof(_Tp)));
}
void
_M_deallocate_node(_Tp* __p)
{
_Node_alloc_type::deallocate(__p, __deque_buf_size(sizeof(_Tp)));
}
_Tp**
_M_allocate_map(size_t __n)
{ return _Map_alloc_type::allocate(__n); }
void
_M_deallocate_map(_Tp** __p, size_t __n)
{ _Map_alloc_type::deallocate(__p, __n); }
_Tp** _M_map;
size_t _M_map_size;
};
/**
* @if maint
* Deque base class. Using _Alloc_traits in the instantiation of the parent
* class provides the compile-time dispatching mentioned in the parent's
* docs. This class provides the unified face for %deque's allocation.
* Deque base class. This class provides the unified face for %deque's
* allocation. This class's constructor and destructor allocate and
* deallocate (but do not initialize) storage. This makes %exception
* safety easier.
*
* Nothing in this class ever constructs or destroys an actual Tp element.
* (Deque handles that itself.) Only/All memory management is performed
@ -441,30 +346,56 @@ namespace __gnu_norm
*/
template<typename _Tp, typename _Alloc>
class _Deque_base
: public _Deque_alloc_base<_Tp,_Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
: public _Alloc
{
public:
typedef _Deque_alloc_base<_Tp,_Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
_Base;
typedef typename _Base::allocator_type allocator_type;
typedef _Alloc allocator_type;
allocator_type get_allocator() const
{ return *static_cast<const _Alloc*>(this); }
typedef _Deque_iterator<_Tp,_Tp&,_Tp*> iterator;
typedef _Deque_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
_Deque_base(const allocator_type& __a, size_t __num_elements)
: _Base(__a), _M_start(), _M_finish()
: _Alloc(__a), _M_start(), _M_finish()
{ _M_initialize_map(__num_elements); }
_Deque_base(const allocator_type& __a)
: _Base(__a), _M_start(), _M_finish() {}
: _Alloc(__a), _M_start(), _M_finish() {}
~_Deque_base();
protected:
typedef typename _Alloc::template rebind<_Tp*>::other _Map_alloc_type;
_Map_alloc_type _M_get_map_allocator() const
{ return _Map_alloc_type(this->get_allocator()); }
_Tp*
_M_allocate_node()
{
return _Alloc::allocate(__deque_buf_size(sizeof(_Tp)));
}
void
_M_deallocate_node(_Tp* __p)
{
_Alloc::deallocate(__p, __deque_buf_size(sizeof(_Tp)));
}
_Tp**
_M_allocate_map(size_t __n)
{ return _M_get_map_allocator().allocate(__n); }
void
_M_deallocate_map(_Tp** __p, size_t __n)
{ _M_get_map_allocator().deallocate(__p, __n); }
protected:
void _M_initialize_map(size_t);
void _M_create_nodes(_Tp** __nstart, _Tp** __nfinish);
void _M_destroy_nodes(_Tp** __nstart, _Tp** __nfinish);
enum { _S_initial_map_size = 8 };
_Tp** _M_map;
size_t _M_map_size;
iterator _M_start;
iterator _M_finish;
};
@ -670,9 +601,7 @@ namespace __gnu_norm
using _Base::_M_deallocate_map;
/** @if maint
* A total of four data members accumulated down the heirarchy. If the
* _Alloc type requires separate instances, then two of them will also be
* included in each deque.
* A total of four data members accumulated down the heirarchy.
* @endif
*/
using _Base::_M_map;

View File

@ -202,36 +202,16 @@ namespace __gnu_norm
}
};
/// @if maint Primary default version. @endif
/**
* @if maint
* See bits/stl_deque.h's _Deque_alloc_base for an explanation.
* See bits/stl_deque.h's _Deque_base for an explanation.
* @endif
*/
template<typename _Tp, typename _Allocator, bool _IsStatic>
class _List_alloc_base
template <typename _Tp, typename _Alloc>
class _List_base
: public _Alloc::template rebind<_List_node<_Tp> >::other
{
public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
allocator_type;
allocator_type
get_allocator() const { return _M_node_allocator; }
_List_alloc_base(const allocator_type& __a)
: _M_node_allocator(__a)
{ }
protected:
_List_node<_Tp>*
_M_get_node()
{ return _M_node_allocator.allocate(1); }
void
_M_put_node(_List_node<_Tp>* __p)
{ _M_node_allocator.deallocate(__p, 1); }
// NOTA BENE
// The stored instance is not actually of "allocator_type"'s type.
// Instead we rebind the type to Allocator<List_node<Tp>>, which
@ -240,69 +220,29 @@ namespace __gnu_norm
// larger), and specializations on Tp may go unused because
// List_node<Tp> is being bound instead.
//
// We put this to the test in get_allocator above; if the two
// types are actually different, there had better be a conversion
// between them.
//
// None of the predefined allocators shipped with the library (as
// of 3.1) use this instantiation anyhow; they're all
// instanceless.
typename _Alloc_traits<_List_node<_Tp>, _Allocator>::allocator_type
_M_node_allocator;
_List_node_base _M_node;
};
/// @if maint Specialization for instanceless allocators. @endif
template<typename _Tp, typename _Allocator>
class _List_alloc_base<_Tp, _Allocator, true>
{
public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
allocator_type;
allocator_type
get_allocator() const { return allocator_type(); }
_List_alloc_base(const allocator_type&)
{ }
protected:
// See comment in primary template class about why this is safe for the
// standard predefined classes.
typedef typename _Alloc_traits<_List_node<_Tp>, _Allocator>::_Alloc_type
_Alloc_type;
// We put this to the test in the constructors and in get_allocator,
// where we use conversions between allocator_type and
// _Node_Alloc_type. The conversion is required by table 32 in [20.1.5].
typedef typename _Alloc::template rebind<_List_node<_Tp> >::other
_Node_Alloc_type;
_List_node<_Tp>*
_M_get_node()
{ return _Alloc_type::allocate(1); }
{ return _Node_Alloc_type::allocate(1); }
void
_M_put_node(_List_node<_Tp>* __p)
{ _Alloc_type::deallocate(__p, 1); }
{ _Node_Alloc_type::deallocate(__p, 1); }
_List_node_base _M_node;
};
/**
* @if maint
* See bits/stl_deque.h's _Deque_base for an explanation.
* @endif
*/
template <typename _Tp, typename _Alloc>
class _List_base
: public _List_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
{
public:
typedef _List_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
_Base;
typedef typename _Base::allocator_type allocator_type;
typedef _Alloc allocator_type;
allocator_type get_allocator() const
{ return allocator_type(*static_cast<const _Node_Alloc_type*>(this)); }
_List_base(const allocator_type& __a)
: _Base(__a)
: _Node_Alloc_type(__a)
{
this->_M_node._M_next = &this->_M_node;
this->_M_node._M_prev = &this->_M_node;

View File

@ -67,70 +67,6 @@
namespace __gnu_norm
{
/// @if maint Primary default version. @endif
/**
* @if maint
* See bits/stl_deque.h's _Deque_alloc_base for an explanation.
* @endif
*/
template<typename _Tp, typename _Allocator, bool _IsStatic>
class _Vector_alloc_base
{
public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
allocator_type;
allocator_type
get_allocator() const { return _M_data_allocator; }
_Vector_alloc_base(const allocator_type& __a)
: _M_data_allocator(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0)
{ }
protected:
allocator_type _M_data_allocator;
_Tp* _M_start;
_Tp* _M_finish;
_Tp* _M_end_of_storage;
_Tp*
_M_allocate(size_t __n) { return _M_data_allocator.allocate(__n); }
void
_M_deallocate(_Tp* __p, size_t __n)
{ if (__p) _M_data_allocator.deallocate(__p, __n); }
};
/// @if maint Specialization for instanceless allocators. @endif
template<typename _Tp, typename _Allocator>
class _Vector_alloc_base<_Tp, _Allocator, true>
{
public:
typedef typename _Alloc_traits<_Tp, _Allocator>::allocator_type
allocator_type;
allocator_type
get_allocator() const { return allocator_type(); }
_Vector_alloc_base(const allocator_type&)
: _M_start(0), _M_finish(0), _M_end_of_storage(0)
{ }
protected:
_Tp* _M_start;
_Tp* _M_finish;
_Tp* _M_end_of_storage;
typedef typename _Alloc_traits<_Tp, _Allocator>::_Alloc_type _Alloc_type;
_Tp*
_M_allocate(size_t __n) { return _Alloc_type::allocate(__n); }
void
_M_deallocate(_Tp* __p, size_t __n) { _Alloc_type::deallocate(__p, __n);}
};
/**
* @if maint
* See bits/stl_deque.h's _Deque_base for an explanation.
@ -138,20 +74,19 @@ namespace __gnu_norm
*/
template<typename _Tp, typename _Alloc>
struct _Vector_base
: public _Vector_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
: public _Alloc
{
public:
typedef _Vector_alloc_base<_Tp, _Alloc,
_Alloc_traits<_Tp, _Alloc>::_S_instanceless>
_Base;
typedef typename _Base::allocator_type allocator_type;
typedef _Alloc allocator_type;
allocator_type
get_allocator() const { return *static_cast<const _Alloc*>(this); }
_Vector_base(const allocator_type& __a)
: _Base(__a) { }
: _Alloc(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) { }
_Vector_base(size_t __n, const allocator_type& __a)
: _Base(__a)
: _Alloc(__a)
{
this->_M_start = this->_M_allocate(__n);
this->_M_finish = this->_M_start;
@ -161,6 +96,18 @@ namespace __gnu_norm
~_Vector_base()
{ _M_deallocate(this->_M_start,
this->_M_end_of_storage - this->_M_start); }
public:
_Tp* _M_start;
_Tp* _M_finish;
_Tp* _M_end_of_storage;
_Tp*
_M_allocate(size_t __n) { return _Alloc::allocate(__n); }
void
_M_deallocate(_Tp* __p, size_t __n)
{ if (__p) _Alloc::deallocate(__p, __n); }
};
@ -209,8 +156,7 @@ namespace __gnu_norm
protected:
/** @if maint
* These two functions and three data members are all from the
* top-most base class, which varies depending on the type of
* %allocator. They should be pretty self-explanatory, as
* base class. They should be pretty self-explanatory, as
* %vector uses a simple contiguous allocation scheme. @endif
*/
using _Base::_M_allocate;
@ -347,8 +293,7 @@ namespace __gnu_norm
}
/// Get a copy of the memory allocation object.
allocator_type
get_allocator() const { return _Base::get_allocator(); }
using _Base::get_allocator;
// iterators
/**

View File

@ -77,7 +77,6 @@ using std::size_t;
using std::ptrdiff_t;
using std::forward_iterator_tag;
using std::input_iterator_tag;
using std::_Alloc_traits;
using std::_Construct;
using std::_Destroy;
using std::distance;
@ -242,10 +241,14 @@ private:
typedef _Hashtable_node<_Val> _Node;
public:
typedef typename _Alloc_traits<_Val,_Alloc>::allocator_type allocator_type;
typedef _Alloc allocator_type;
allocator_type get_allocator() const { return _M_node_allocator; }
private:
typename _Alloc_traits<_Node, _Alloc>::allocator_type _M_node_allocator;
typedef typename _Alloc::template rebind<_Node>::other _Node_Alloc;
typedef typename _Alloc::template rebind<_Node*>::other _Nodeptr_Alloc;
typedef vector<_Node*, _Nodeptr_Alloc> _Vector_type;
_Node_Alloc _M_node_allocator;
_Node* _M_get_node() { return _M_node_allocator.allocate(1); }
void _M_put_node(_Node* __p) { _M_node_allocator.deallocate(__p, 1); }
@ -253,7 +256,7 @@ private:
hasher _M_hash;
key_equal _M_equals;
_ExtractKey _M_get_key;
vector<_Node*,_Alloc> _M_buckets;
_Vector_type _M_buckets;
size_type _M_num_elements;
public:
@ -876,8 +879,7 @@ void hashtable<_Val,_Key,_HF,_Ex,_Eq,_All>
if (__num_elements_hint > __old_n) {
const size_type __n = _M_next_size(__num_elements_hint);
if (__n > __old_n) {
vector<_Node*, _All> __tmp(__n, (_Node*)(0),
_M_buckets.get_allocator());
_Vector_type __tmp(__n, (_Node*)(0), _M_buckets.get_allocator());
try {
for (size_type __bucket = 0; __bucket < __old_n; ++__bucket) {
_Node* __first = _M_buckets[__bucket];