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
#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.
template <class Allocator> struct allocator_value_type
@ -66,7 +78,7 @@ namespace boost {
typedef typename Allocator::const_reference type;
};
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
template <>
struct allocator_value_type<int>
@ -98,7 +110,7 @@ namespace boost {
typedef int type;
};
#endif
#endif
template <class Allocator>
struct allocator_constructor
@ -109,7 +121,12 @@ namespace boost {
pointer ptr_;
allocator_constructor(Allocator& a)
: alloc_(a), ptr_() {}
: alloc_(a), ptr_()
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(ptr_);
#endif
}
~allocator_constructor() {
if (ptr_) alloc_.deallocate(ptr_, 1);
@ -117,10 +134,11 @@ namespace boost {
template <class V>
pointer construct(V const& v) {
BOOST_ASSERT(!ptr_);
pointer p = alloc_.allocate(1);
ptr_ = p;
alloc_.construct(p, v);
ptr_ = pointer();
reset(ptr_);
return p;
}
@ -128,7 +146,7 @@ namespace boost {
pointer release()
{
pointer p = ptr_;
ptr_ = pointer();
reset(ptr_);
return p;
}
};
@ -144,7 +162,13 @@ namespace boost {
std::size_t length_;
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() {
if (ptr_) {
@ -158,6 +182,7 @@ namespace boost {
template <class V>
void construct(V const& v, std::size_t l)
{
BOOST_ASSERT(!ptr_);
length_ = l;
ptr_ = alloc_.allocate(length_);
pointer end = ptr_ + length_;
@ -173,9 +198,12 @@ namespace boost {
pointer release()
{
pointer p(ptr_);
ptr_ = pointer();
reset(ptr_);
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/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/detail/workaround.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>
#endif
@ -49,6 +50,12 @@
#include <stdexcept>
#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 unordered_detail {
template <class T> struct type_wrapper {};
@ -56,18 +63,16 @@ namespace boost {
const static std::size_t default_initial_bucket_count = 50;
inline std::size_t next_prime(std::size_t n);
// I bet this is already in boost somewhere.
template <class T>
void hash_swap(T& x, T& y)
inline void hash_swap(T& x, T& y)
{
using namespace std;
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)() :
static_cast<std::size_t>(f);
}
@ -162,9 +167,12 @@ namespace boost {
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.
BOOST_ASSERT(!x.next_);
@ -205,6 +213,9 @@ namespace boost {
: node_alloc_(n), bucket_alloc_(b), value_alloc_(n),
ptr_(), value_allocated_(false), bucket_allocated_(false)
{
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
unordered_detail::reset(ptr_);
#endif
}
~node_constructor()
@ -224,7 +235,7 @@ namespace boost {
template <class V>
void construct(V const& v)
{
assert(!ptr_);
BOOST_ASSERT(!ptr_);
value_allocated_ = bucket_allocated_ = false;
ptr_ = node_alloc_.allocate(1);
@ -242,9 +253,13 @@ namespace boost {
link_ptr release()
{
node_ptr p = ptr_;
ptr_ = node_ptr();
unordered_detail::reset(ptr_);
return bucket_alloc_.address(*p);
}
private:
node_constructor(node_constructor const&);
node_constructor& operator=(node_constructor const&);
};
#else
class node_constructor
@ -262,14 +277,19 @@ namespace boost {
link_ptr node_pointer_;
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)
: node_pointer_(n) {}
bool not_finished() const
{
return node_pointer_;
return node_pointer_ ? true : false;
}
bool operator==(local_iterator_base const& x) const
@ -318,7 +338,7 @@ namespace boost {
bool not_finished() const
{
return *prev_ptr;
return *prev_ptr ? true : false;
}
value_type& operator*() const
@ -435,7 +455,9 @@ namespace boost {
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)
buckets_[bucket_count_].next_ = buckets_ + bucket_count_;
#else
@ -454,8 +476,10 @@ namespace boost {
void move_end_marker(hash_table_data& src)
{
BOOST_ASSERT(buckets_ && !buckets_[bucket_count_].next_);
BOOST_ASSERT(src.buckets_ && src.buckets_[src.bucket_count_].next_);
BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(buckets_) &&
!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)
buckets_[bucket_count_].next_ = buckets_ + bucket_count_;
@ -469,12 +493,13 @@ namespace boost {
}
#endif
src.buckets_[src.bucket_count_].next_ = link_ptr();
unordered_detail::reset(src.buckets_[src.bucket_count_].next_);
}
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(!is_pointer_allocator)
@ -482,7 +507,7 @@ namespace boost {
buckets_[bucket_count_].next_), 1);
#endif
buckets_[bucket_count_].next_ = link_ptr();
unordered_detail::reset(buckets_[bucket_count_].next_);
}
private:
@ -847,7 +872,7 @@ namespace boost {
class functions
{
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
boost::compressed_pair<hasher, key_equal> functions_;
#else
std::pair<hasher, key_equal> functions_;
@ -860,7 +885,7 @@ namespace boost {
hasher const& hash_function() const
{
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
return functions_.first();
#else
return functions_.first;
@ -869,7 +894,7 @@ namespace boost {
key_equal const& key_eq() const
{
#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300)
return functions_.second();
#else
return functions_.second;
@ -927,7 +952,7 @@ namespace boost {
};
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)
{
return n;
@ -1110,8 +1135,9 @@ namespace boost {
// accessors
// TODO: This creates an unnecessary copy.
// no throw
node_allocator const& get_allocator() const
value_allocator get_allocator() const
{
return this->node_alloc_;
}
@ -1336,10 +1362,8 @@ namespace boost {
static void copy_buckets(data const& src, data& dst, functions const& f)
{
BOOST_ASSERT(dst.size_ == 0);
// no throw:
bucket_ptr end = src.buckets_ + src.bucket_count_;
hasher const& hf = f.hash_function();
// no throw:
@ -1565,16 +1589,29 @@ namespace boost {
private:
// basic exception safety
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class I>
void insert_for_range(I i, I j,
boost::random_access_traversal_tag)
{
reserve(size() + (j - i)); // basic/strong
for (; i != j; ++i) unchecked_insert(*i); // 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
}
}
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>
void insert_for_range(I i, I j,
boost::incrementable_traversal_tag)
@ -1584,7 +1621,8 @@ namespace boost {
public:
// basic exception safety
// if hash function throws, or inserting > 1 element, basic exception safety
// strong otherwise
template <class InputIterator>
void insert(InputIterator i, InputIterator j)
{
@ -1927,5 +1965,7 @@ namespace boost {
} // namespace boost::unordered_detail
} // namespace boost
#undef BOOST_HASH_BORLAND_BOOL
#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
* 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>
unordered_map(InputIterator f, InputIterator l,
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
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>
unordered_multimap(InputIterator f, InputIterator l,
size_type n = boost::unordered_detail::default_initial_bucket_count,
size_type n,
const hasher &hf = hasher(),
const key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())

View File

@ -81,8 +81,14 @@ namespace boost
}
template <class InputIterator>
unordered_set(InputIterator f, InputIterator l,
size_type n = boost::unordered_detail::default_initial_bucket_count,
unordered_set(InputIterator f, InputIterator l)
: 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 key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())
@ -355,8 +361,14 @@ namespace boost
}
template <class InputIterator>
unordered_multiset(InputIterator f, InputIterator l,
size_type n = boost::unordered_detail::default_initial_bucket_count,
unordered_multiset(InputIterator f, InputIterator l)
: 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 key_equal &eql = key_equal(),
const allocator_type &a = allocator_type())