New version of the unordered containers. Includes workarounds for older

compilers. Also follows the exception requirements closer.


[SVN r2875]
This commit is contained in:
Daniel James
2006-02-26 18:33:49 +00:00
parent 4c3417468b
commit ee93aad35a
4 changed files with 137 additions and 43 deletions

View File

@ -39,6 +39,18 @@ namespace boost {
}; };
#endif #endif
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
template <class T>
inline void reset(T& x) { x = T(); }
#else
template <class T>
inline void reset_impl(T& x, ...) { x = T(); }
template <class T>
inline void reset_impl(T*& x, int) { x = 0; }
template <class T>
inline void reset(T& x) { reset_impl(x); }
#endif
// Work around for Microsoft's ETI bug. // Work around for Microsoft's ETI bug.
template <class Allocator> struct allocator_value_type template <class Allocator> struct allocator_value_type
@ -66,7 +78,7 @@ namespace boost {
typedef typename Allocator::const_reference type; typedef typename Allocator::const_reference type;
}; };
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG) #if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
template <> template <>
struct allocator_value_type<int> struct allocator_value_type<int>
@ -98,7 +110,7 @@ namespace boost {
typedef int type; typedef int type;
}; };
#endif #endif
template <class Allocator> template <class Allocator>
struct allocator_constructor struct allocator_constructor
@ -109,7 +121,12 @@ namespace boost {
pointer ptr_; pointer ptr_;
allocator_constructor(Allocator& a) allocator_constructor(Allocator& a)
: alloc_(a), ptr_() {} : alloc_(a), ptr_()
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(ptr_);
#endif
}
~allocator_constructor() { ~allocator_constructor() {
if (ptr_) alloc_.deallocate(ptr_, 1); if (ptr_) alloc_.deallocate(ptr_, 1);
@ -117,10 +134,11 @@ namespace boost {
template <class V> template <class V>
pointer construct(V const& v) { pointer construct(V const& v) {
BOOST_ASSERT(!ptr_);
pointer p = alloc_.allocate(1); pointer p = alloc_.allocate(1);
ptr_ = p; ptr_ = p;
alloc_.construct(p, v); alloc_.construct(p, v);
ptr_ = pointer(); reset(ptr_);
return p; return p;
} }
@ -128,7 +146,7 @@ namespace boost {
pointer release() pointer release()
{ {
pointer p = ptr_; pointer p = ptr_;
ptr_ = pointer(); reset(ptr_);
return p; return p;
} }
}; };
@ -144,7 +162,13 @@ namespace boost {
std::size_t length_; std::size_t length_;
allocator_array_constructor(Allocator& a) allocator_array_constructor(Allocator& a)
: alloc_(a), ptr_(), constructed_(), length_(0) {} : alloc_(a), ptr_(), constructed_(), length_(0)
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(constructed_);
unordered_detail::reset(ptr_);
#endif
}
~allocator_array_constructor() { ~allocator_array_constructor() {
if (ptr_) { if (ptr_) {
@ -158,6 +182,7 @@ namespace boost {
template <class V> template <class V>
void construct(V const& v, std::size_t l) void construct(V const& v, std::size_t l)
{ {
BOOST_ASSERT(!ptr_);
length_ = l; length_ = l;
ptr_ = alloc_.allocate(length_); ptr_ = alloc_.allocate(length_);
pointer end = ptr_ + length_; pointer end = ptr_ + length_;
@ -173,9 +198,12 @@ namespace boost {
pointer release() pointer release()
{ {
pointer p(ptr_); pointer p(ptr_);
ptr_ = pointer(); reset(ptr_);
return p; return p;
} }
private:
allocator_array_constructor(allocator_array_constructor const&);
allocator_array_constructor& operator=(allocator_array_constructor const&);
}; };
} }
} }

View File

@ -33,10 +33,11 @@
#include <boost/type_traits/is_same.hpp> #include <boost/type_traits/is_same.hpp>
#include <boost/mpl/if.hpp> #include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp> #include <boost/mpl/and.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/mpl/aux_/config/eti.hpp> #include <boost/mpl/aux_/config/eti.hpp>
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
#include <boost/compressed_pair.hpp> #include <boost/compressed_pair.hpp>
#endif #endif
@ -49,6 +50,12 @@
#include <stdexcept> #include <stdexcept>
#endif #endif
#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551)
#define BOOST_HASH_BORLAND_BOOL(x) (bool)(x)
#else
#define BOOST_HASH_BORLAND_BOOL(x) x
#endif
namespace boost { namespace boost {
namespace unordered_detail { namespace unordered_detail {
template <class T> struct type_wrapper {}; template <class T> struct type_wrapper {};
@ -56,18 +63,16 @@ namespace boost {
const static std::size_t default_initial_bucket_count = 50; const static std::size_t default_initial_bucket_count = 50;
inline std::size_t next_prime(std::size_t n); inline std::size_t next_prime(std::size_t n);
// I bet this is already in boost somewhere.
template <class T> template <class T>
void hash_swap(T& x, T& y) inline void hash_swap(T& x, T& y)
{ {
using namespace std; using namespace std;
swap(x, y); swap(x, y);
} }
std::size_t float_to_size_t(float f) inline std::size_t float_to_size_t(float f)
{ {
return f > (std::numeric_limits<std::size_t>::max)() ? return f > static_cast<float>((std::numeric_limits<std::size_t>::max)()) ?
(std::numeric_limits<std::size_t>::max)() : (std::numeric_limits<std::size_t>::max)() :
static_cast<std::size_t>(f); static_cast<std::size_t>(f);
} }
@ -162,9 +167,12 @@ namespace boost {
bucket() : next_() bucket() : next_()
{ {
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(next_);
#endif
} }
bucket(bucket const& x) : next_() bucket(bucket const& x) : next_(x.next_)
{ {
// Only copy construct when allocating. // Only copy construct when allocating.
BOOST_ASSERT(!x.next_); BOOST_ASSERT(!x.next_);
@ -205,6 +213,9 @@ namespace boost {
: node_alloc_(n), bucket_alloc_(b), value_alloc_(n), : node_alloc_(n), bucket_alloc_(b), value_alloc_(n),
ptr_(), value_allocated_(false), bucket_allocated_(false) ptr_(), value_allocated_(false), bucket_allocated_(false)
{ {
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(ptr_);
#endif
} }
~node_constructor() ~node_constructor()
@ -224,7 +235,7 @@ namespace boost {
template <class V> template <class V>
void construct(V const& v) void construct(V const& v)
{ {
assert(!ptr_); BOOST_ASSERT(!ptr_);
value_allocated_ = bucket_allocated_ = false; value_allocated_ = bucket_allocated_ = false;
ptr_ = node_alloc_.allocate(1); ptr_ = node_alloc_.allocate(1);
@ -242,9 +253,13 @@ namespace boost {
link_ptr release() link_ptr release()
{ {
node_ptr p = ptr_; node_ptr p = ptr_;
ptr_ = node_ptr(); unordered_detail::reset(ptr_);
return bucket_alloc_.address(*p); return bucket_alloc_.address(*p);
} }
private:
node_constructor(node_constructor const&);
node_constructor& operator=(node_constructor const&);
}; };
#else #else
class node_constructor class node_constructor
@ -262,14 +277,19 @@ namespace boost {
link_ptr node_pointer_; link_ptr node_pointer_;
local_iterator_base() local_iterator_base()
: node_pointer_() {} : node_pointer_()
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(node_pointer_);
#endif
}
explicit local_iterator_base(link_ptr n) explicit local_iterator_base(link_ptr n)
: node_pointer_(n) {} : node_pointer_(n) {}
bool not_finished() const bool not_finished() const
{ {
return node_pointer_; return node_pointer_ ? true : false;
} }
bool operator==(local_iterator_base const& x) const bool operator==(local_iterator_base const& x) const
@ -318,7 +338,7 @@ namespace boost {
bool not_finished() const bool not_finished() const
{ {
return *prev_ptr; return *prev_ptr ? true : false;
} }
value_type& operator*() const value_type& operator*() const
@ -435,7 +455,9 @@ namespace boost {
void add_end_marker() void add_end_marker()
{ {
BOOST_ASSERT(buckets_ && !buckets_[bucket_count_].next_); BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(buckets_) &&
!buckets_[bucket_count_].next_);
#if !defined(BOOST_UNORDERED_PARANOID) #if !defined(BOOST_UNORDERED_PARANOID)
buckets_[bucket_count_].next_ = buckets_ + bucket_count_; buckets_[bucket_count_].next_ = buckets_ + bucket_count_;
#else #else
@ -454,8 +476,10 @@ namespace boost {
void move_end_marker(hash_table_data& src) void move_end_marker(hash_table_data& src)
{ {
BOOST_ASSERT(buckets_ && !buckets_[bucket_count_].next_); BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(buckets_) &&
BOOST_ASSERT(src.buckets_ && src.buckets_[src.bucket_count_].next_); !buckets_[bucket_count_].next_);
BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(src.buckets_) &&
BOOST_HASH_BORLAND_BOOL(src.buckets_[src.bucket_count_].next_));
#if !defined(BOOST_UNORDERED_PARANOID) #if !defined(BOOST_UNORDERED_PARANOID)
buckets_[bucket_count_].next_ = buckets_ + bucket_count_; buckets_[bucket_count_].next_ = buckets_ + bucket_count_;
@ -469,12 +493,13 @@ namespace boost {
} }
#endif #endif
src.buckets_[src.bucket_count_].next_ = link_ptr(); unordered_detail::reset(src.buckets_[src.bucket_count_].next_);
} }
void remove_end_marker() void remove_end_marker()
{ {
BOOST_ASSERT(buckets_ && buckets_[bucket_count_].next_); BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(buckets_) &&
BOOST_HASH_BORLAND_BOOL(buckets_[bucket_count_].next_));
#if defined(BOOST_UNORDERED_PARANOID) #if defined(BOOST_UNORDERED_PARANOID)
if(!is_pointer_allocator) if(!is_pointer_allocator)
@ -482,7 +507,7 @@ namespace boost {
buckets_[bucket_count_].next_), 1); buckets_[bucket_count_].next_), 1);
#endif #endif
buckets_[bucket_count_].next_ = link_ptr(); unordered_detail::reset(buckets_[bucket_count_].next_);
} }
private: private:
@ -847,7 +872,7 @@ namespace boost {
class functions class functions
{ {
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
boost::compressed_pair<hasher, key_equal> functions_; boost::compressed_pair<hasher, key_equal> functions_;
#else #else
std::pair<hasher, key_equal> functions_; std::pair<hasher, key_equal> functions_;
@ -860,7 +885,7 @@ namespace boost {
hasher const& hash_function() const hasher const& hash_function() const
{ {
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
return functions_.first(); return functions_.first();
#else #else
return functions_.first; return functions_.first;
@ -869,7 +894,7 @@ namespace boost {
key_equal const& key_eq() const key_equal const& key_eq() const
{ {
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
return functions_.second(); return functions_.second();
#else #else
return functions_.second; return functions_.second;
@ -927,7 +952,7 @@ namespace boost {
}; };
template <class I> template <class I>
std::size_t initial_size(I i, I j, size_type n, std::size_t initial_size(I, I, size_type n,
boost::incrementable_traversal_tag) boost::incrementable_traversal_tag)
{ {
return n; return n;
@ -1110,8 +1135,9 @@ namespace boost {
// accessors // accessors
// TODO: This creates an unnecessary copy.
// no throw // no throw
node_allocator const& get_allocator() const value_allocator get_allocator() const
{ {
return this->node_alloc_; return this->node_alloc_;
} }
@ -1336,10 +1362,8 @@ namespace boost {
static void copy_buckets(data const& src, data& dst, functions const& f) static void copy_buckets(data const& src, data& dst, functions const& f)
{ {
BOOST_ASSERT(dst.size_ == 0); BOOST_ASSERT(dst.size_ == 0);
// no throw: // no throw:
bucket_ptr end = src.buckets_ + src.bucket_count_; bucket_ptr end = src.buckets_ + src.bucket_count_;
hasher const& hf = f.hash_function(); hasher const& hf = f.hash_function();
// no throw: // no throw:
@ -1565,16 +1589,29 @@ namespace boost {
private: private:
// basic exception safety // if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class I> template <class I>
void insert_for_range(I i, I j, void insert_for_range(I i, I j,
boost::random_access_traversal_tag) boost::random_access_traversal_tag)
{ {
reserve(size() + (j - i)); // basic/strong if(EquivalentKeys) {
std::size_t distance = j - i;
if(distance == 1) {
insert(*i);
}
else {
reserve(size() + distance); // basic/strong
for (; i != j; ++i) unchecked_insert(*i); // strong for (; i != j; ++i) unchecked_insert(*i); // strong
} }
}
else {
for (; i != j; ++i) insert_unique(*i); // basic/strong
}
}
// basic exception safety // if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class I> template <class I>
void insert_for_range(I i, I j, void insert_for_range(I i, I j,
boost::incrementable_traversal_tag) boost::incrementable_traversal_tag)
@ -1584,7 +1621,8 @@ namespace boost {
public: public:
// basic exception safety // if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class InputIterator> template <class InputIterator>
void insert(InputIterator i, InputIterator j) void insert(InputIterator i, InputIterator j)
{ {
@ -1927,5 +1965,7 @@ namespace boost {
} // namespace boost::unordered_detail } // namespace boost::unordered_detail
} // namespace boost } // namespace boost
#undef BOOST_HASH_BORLAND_BOOL
#endif // BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED #endif // BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED

View File

@ -107,9 +107,16 @@ namespace boost
* the hash function and eq as the key equality predicate, and inserts * the hash function and eq as the key equality predicate, and inserts
* elements from [i,j) into it. a is used as the allocator. * elements from [i,j) into it. a is used as the allocator.
*/ */
template <class InputIterator>
unordered_map(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator> template <class InputIterator>
unordered_map(InputIterator f, InputIterator l, unordered_map(InputIterator f, InputIterator l,
size_type n = boost::unordered_detail::default_initial_bucket_count, size_type n,
const hasher &hf = hasher(), const hasher &hf = hasher(),
const key_equal &eql = key_equal(), const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type()) const allocator_type &a = allocator_type())
@ -388,9 +395,16 @@ namespace boost
{ {
} }
template <class InputIterator>
unordered_multimap(InputIterator f, InputIterator l)
: base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator> template <class InputIterator>
unordered_multimap(InputIterator f, InputIterator l, unordered_multimap(InputIterator f, InputIterator l,
size_type n = boost::unordered_detail::default_initial_bucket_count, size_type n,
const hasher &hf = hasher(), const hasher &hf = hasher(),
const key_equal &eql = key_equal(), const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type()) const allocator_type &a = allocator_type())

View File

@ -81,8 +81,14 @@ namespace boost
} }
template <class InputIterator> template <class InputIterator>
unordered_set(InputIterator f, InputIterator l, unordered_set(InputIterator f, InputIterator l)
size_type n = boost::unordered_detail::default_initial_bucket_count, : base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l, size_type n,
const hasher &hf = hasher(), const hasher &hf = hasher(),
const key_equal &eql = key_equal(), const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type()) const allocator_type &a = allocator_type())
@ -355,8 +361,14 @@ namespace boost
} }
template <class InputIterator> template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l, unordered_multiset(InputIterator f, InputIterator l)
size_type n = boost::unordered_detail::default_initial_bucket_count, : base(f, l, boost::unordered_detail::default_initial_bucket_count,
hasher(), key_equal(), allocator_type())
{
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l, size_type n,
const hasher &hf = hasher(), const hasher &hf = hasher(),
const key_equal &eql = key_equal(), const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type()) const allocator_type &a = allocator_type())