You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
238 lines
7.6 KiB
238 lines
7.6 KiB
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// (C) Copyright Ion Gaztanaga 2007-2009 |
|
// |
|
// Distributed under the Boost Software License, Version 1.0. |
|
// (See accompanying file LICENSE_1_0.txt or copy at |
|
// http://www.boost.org/LICENSE_1_0.txt) |
|
// |
|
// See http://www.boost.org/libs/intrusive for documentation. |
|
// |
|
///////////////////////////////////////////////////////////////////////////// |
|
|
|
#ifndef BOOST_INTRUSIVE_HASHTABLE_NODE_HPP |
|
#define BOOST_INTRUSIVE_HASHTABLE_NODE_HPP |
|
|
|
#include <boost/intrusive/detail/config_begin.hpp> |
|
#include <iterator> |
|
#include <boost/intrusive/detail/assert.hpp> |
|
#include <boost/intrusive/detail/pointer_to_other.hpp> |
|
#include <boost/intrusive/circular_list_algorithms.hpp> |
|
#include <boost/intrusive/detail/mpl.hpp> |
|
#include <boost/intrusive/detail/utilities.hpp> |
|
#include <boost/intrusive/detail/slist_node.hpp> //remove-me |
|
#include <cstddef> |
|
#include <boost/pointer_cast.hpp> |
|
#include <boost/move/move.hpp> |
|
|
|
|
|
namespace boost { |
|
namespace intrusive { |
|
namespace detail { |
|
|
|
template<int Dummy = 0> |
|
struct prime_list_holder |
|
{ |
|
static const std::size_t prime_list[]; |
|
static const std::size_t prime_list_size; |
|
}; |
|
|
|
template<int Dummy> |
|
const std::size_t prime_list_holder<Dummy>::prime_list[] = { |
|
3ul, 7ul, 11ul, 17ul, 29ul, |
|
53ul, 97ul, 193ul, 389ul, 769ul, |
|
1543ul, 3079ul, 6151ul, 12289ul, 24593ul, |
|
49157ul, 98317ul, 196613ul, 393241ul, 786433ul, |
|
1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, |
|
50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, |
|
1610612741ul, 3221225473ul, 4294967291ul }; |
|
|
|
template<int Dummy> |
|
const std::size_t prime_list_holder<Dummy>::prime_list_size |
|
= sizeof(prime_list)/sizeof(std::size_t); |
|
|
|
template <class Slist> |
|
struct bucket_impl : public Slist |
|
{ |
|
typedef Slist slist_type; |
|
bucket_impl() |
|
{} |
|
|
|
bucket_impl(const bucket_impl &) |
|
{} |
|
|
|
~bucket_impl() |
|
{ |
|
//This bucket is still being used! |
|
BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty()); |
|
} |
|
|
|
bucket_impl &operator=(const bucket_impl&) |
|
{ |
|
//This bucket is still in use! |
|
BOOST_INTRUSIVE_INVARIANT_ASSERT(Slist::empty()); |
|
//Slist::clear(); |
|
return *this; |
|
} |
|
}; |
|
|
|
template<class Slist> |
|
struct bucket_traits_impl |
|
{ |
|
private: |
|
BOOST_COPYABLE_AND_MOVABLE(bucket_traits_impl) |
|
|
|
public: |
|
/// @cond |
|
typedef typename boost::pointer_to_other |
|
< typename Slist::pointer, bucket_impl<Slist> >::type bucket_ptr; |
|
typedef typename Slist::size_type size_type; |
|
/// @endcond |
|
|
|
bucket_traits_impl(bucket_ptr buckets, size_type len) |
|
: buckets_(buckets), buckets_len_(len) |
|
{} |
|
|
|
bucket_traits_impl(BOOST_RV_REF(bucket_traits_impl) x) |
|
: buckets_(x.buckets_), buckets_len_(x.buckets_len_) |
|
{ x.buckets_ = bucket_ptr(0); x.buckets_len_ = 0; } |
|
|
|
bucket_traits_impl& operator=(BOOST_RV_REF(bucket_traits_impl) x) |
|
{ |
|
buckets_ = x.buckets_; buckets_len_ = x.buckets_len_; |
|
x.buckets_ = bucket_ptr(0); x.buckets_len_ = 0; return *this; |
|
} |
|
|
|
bucket_traits_impl& operator=(BOOST_COPY_ASSIGN_REF(bucket_traits_impl) x) |
|
{ |
|
buckets_ = x.buckets_; buckets_len_ = x.buckets_len_; return *this; |
|
} |
|
|
|
bucket_ptr bucket_begin() const |
|
{ return buckets_; } |
|
|
|
size_type bucket_count() const |
|
{ return buckets_len_; } |
|
|
|
private: |
|
bucket_ptr buckets_; |
|
size_type buckets_len_; |
|
}; |
|
|
|
template<class Container, bool IsConst> |
|
class hashtable_iterator |
|
: public std::iterator |
|
< std::forward_iterator_tag |
|
, typename Container::value_type |
|
, typename std::iterator_traits<typename Container::value_type*>::difference_type |
|
, typename detail::add_const_if_c |
|
<typename Container::value_type, IsConst>::type * |
|
, typename detail::add_const_if_c |
|
<typename Container::value_type, IsConst>::type & |
|
> |
|
{ |
|
typedef typename Container::real_value_traits real_value_traits; |
|
typedef typename Container::siterator siterator; |
|
typedef typename Container::const_siterator const_siterator; |
|
typedef typename Container::bucket_type bucket_type; |
|
typedef typename boost::pointer_to_other |
|
< typename Container::pointer, const Container>::type const_cont_ptr; |
|
typedef typename Container::size_type size_type; |
|
|
|
static typename Container::node_ptr downcast_bucket(typename bucket_type::node_ptr p) |
|
{ |
|
// This still fails in gcc < 4.4 so forget about it |
|
// using ::boost::static_pointer_cast; |
|
// return static_pointer_cast<typename Container::node>(p); |
|
return typename Container::node_ptr(&static_cast<typename Container::node&>(*p)); |
|
} |
|
|
|
public: |
|
typedef typename Container::value_type value_type; |
|
typedef typename detail::add_const_if_c |
|
<typename Container::value_type, IsConst>::type *pointer; |
|
typedef typename detail::add_const_if_c |
|
<typename Container::value_type, IsConst>::type &reference; |
|
|
|
hashtable_iterator () |
|
{} |
|
|
|
explicit hashtable_iterator(siterator ptr, const Container *cont) |
|
: slist_it_ (ptr), cont_ (cont) |
|
{} |
|
|
|
hashtable_iterator(const hashtable_iterator<Container, false> &other) |
|
: slist_it_(other.slist_it()), cont_(other.get_container()) |
|
{} |
|
|
|
const siterator &slist_it() const |
|
{ return slist_it_; } |
|
|
|
hashtable_iterator<Container, false> unconst() const |
|
{ return hashtable_iterator<Container, false>(this->slist_it(), this->get_container()); } |
|
|
|
public: |
|
hashtable_iterator& operator++() |
|
{ this->increment(); return *this; } |
|
|
|
hashtable_iterator operator++(int) |
|
{ |
|
hashtable_iterator result (*this); |
|
this->increment(); |
|
return result; |
|
} |
|
|
|
friend bool operator== (const hashtable_iterator& i, const hashtable_iterator& i2) |
|
{ return i.slist_it_ == i2.slist_it_; } |
|
|
|
friend bool operator!= (const hashtable_iterator& i, const hashtable_iterator& i2) |
|
{ return !(i == i2); } |
|
|
|
reference operator*() const |
|
{ return *this->operator ->(); } |
|
|
|
pointer operator->() const |
|
{ return detail::boost_intrusive_get_pointer(this->get_real_value_traits()->to_value_ptr(downcast_bucket(slist_it_.pointed_node()))); } |
|
|
|
const Container *get_container() const |
|
{ return detail::boost_intrusive_get_pointer(cont_); } |
|
|
|
const real_value_traits *get_real_value_traits() const |
|
{ return &this->get_container()->get_real_value_traits(); } |
|
|
|
private: |
|
void increment() |
|
{ |
|
const Container *cont = detail::boost_intrusive_get_pointer(cont_); |
|
bucket_type* buckets = detail::boost_intrusive_get_pointer(cont->bucket_pointer()); |
|
size_type buckets_len = cont->bucket_count(); |
|
|
|
++slist_it_; |
|
if(buckets[0].cend().pointed_node() <= slist_it_.pointed_node() && |
|
slist_it_.pointed_node()<= buckets[buckets_len].cend().pointed_node() ){ |
|
//Now get the bucket_impl from the iterator |
|
const bucket_type &b = static_cast<const bucket_type&> |
|
(bucket_type::slist_type::container_from_end_iterator(slist_it_)); |
|
|
|
//Now just calculate the index b has in the bucket array |
|
size_type n_bucket = static_cast<size_type>(&b - &buckets[0]); |
|
do{ |
|
if (++n_bucket == buckets_len){ |
|
slist_it_ = (&buckets[0] + buckets_len)->end(); |
|
break; |
|
} |
|
slist_it_ = buckets[n_bucket].begin(); |
|
} |
|
while (slist_it_ == buckets[n_bucket].end()); |
|
} |
|
} |
|
|
|
siterator slist_it_; |
|
const_cont_ptr cont_; |
|
}; |
|
|
|
} //namespace detail { |
|
} //namespace intrusive { |
|
} //namespace boost { |
|
|
|
#endif
|
|
|