8#ifndef ADOBE_CLOSED_HASH_HPP
9#define ADOBE_CLOSED_HASH_HPP
20#include <initializer_list>
24#include <boost/compressed_pair.hpp>
25#include <boost/iterator/iterator_adaptor.hpp>
26#include <boost/iterator/iterator_facade.hpp>
27#include <boost/next_prior.hpp>
28#include <boost/operators.hpp>
39#include <adobe/implementation/swap.hpp>
47namespace implementation {
51template <
typename T,
typename V>
52class closed_hash_iterator :
public boost::iterator_facade<closed_hash_iterator<T, V>, V,
53 std::bidirectional_iterator_tag> {
54 typedef boost::iterator_facade<closed_hash_iterator<T, V>, V, std::bidirectional_iterator_tag>
57 typedef typename T::node_t node_t;
60 typedef typename inherited_t::reference reference;
61 typedef typename inherited_t::difference_type difference_type;
62 typedef typename inherited_t::value_type value_type;
64 closed_hash_iterator() : node_m(0) {}
67 closed_hash_iterator(
const closed_hash_iterator<T, O>& x) : node_m(x.node_m) {}
78 reference dereference()
const {
return node_m->value_m; }
79 void increment() { node_m = node_m->next(); }
80 void decrement() { node_m = node_m->prior(); }
83 bool equal(
const closed_hash_iterator<T, O>& y)
const {
84 return node_m == y.node_m;
87 std::size_t state()
const {
return node_m->state(); }
88 void set_state(std::size_t x) {
return node_m->set_state(x); }
90 explicit closed_hash_iterator(node_t* node) : node_m(node) {}
92 friend class version_1::closed_hash_set<value_type, typename T::key_transform,
93 typename T::hasher, typename T::key_equal,
94 typename T::allocator_type>;
95 friend class boost::iterator_core_access;
96 friend struct unsafe::set_next_fn<closed_hash_iterator>;
107template <
typename T,
typename V>
108struct set_next_fn<implementation::closed_hash_iterator<T, V>> {
109 typedef typename implementation::closed_hash_iterator<T, V> iterator;
111 void operator()(iterator x, iterator y)
const {
set_next(*x.node_m, *y.node_m); }
118#ifndef ADOBE_NO_DOCUMENTATION
120inline namespace version_1 {
145template <
typename T,
typename KeyTransform,
typename Hash,
typename Pred,
typename A>
147 : boost::equality_comparable<closed_hash_set<T, KeyTransform, Hash, Pred, A>,
148 closed_hash_set<T, KeyTransform, Hash, Pred, A>,
149 empty_base<closed_hash_set<T, KeyTransform, Hash, Pred, A>>> {
153 using key_type = std::remove_reference_t<adobe::invoke_result_t<KeyTransform, T>>;
169 typedef implementation::closed_hash_iterator<closed_hash_set, value_type>
iterator;
170 typedef implementation::closed_hash_iterator<closed_hash_set, const value_type>
const_iterator;
176 enum { state_free = 0, state_home = 1, state_misplaced = 2 };
178 template <
typename U>
179 struct list_node_base {
181 next_m =
static_cast<U*
>(
this);
182 prior_m =
static_cast<U*
>(
this);
185 U* address() {
return static_cast<U*
>(
this); }
186 const U* address()
const {
return static_cast<const U*
>(
this); }
188 operator U&() {
return *
static_cast<U*
>(
this); }
189 operator const U&()
const {
return *
static_cast<const U*
>(
this); }
191 friend inline void set_next(U& x, U& y) {
192 x.next_m =
reinterpret_cast<U*
>(std::uintptr_t(&y) | std::uintptr_t(x.state()));
196 friend inline void set_next_raw(U& x, U& y) {
201 std::size_t state()
const {
202 return std::size_t(std::uintptr_t(next_m) & std::uintptr_t(0x03UL));
204 void set_state(std::size_t x) {
206 next_m =
reinterpret_cast<U*
>(std::uintptr_t(next()) | std::uintptr_t(x));
210 return reinterpret_cast<U*
>(
reinterpret_cast<std::uintptr_t
>(next_m) &
211 ~std::uintptr_t(0x03UL));
213 U* prior()
const {
return prior_m; }
220 struct node_t : list_node_base<node_t> {
224 typedef list_node_base<node_t> node_base_t;
240 static_assert(!(
sizeof(A) ==
sizeof(
void*) ||
sizeof(A) == 0) ||
243 2 *
sizeof(std::size_t))));
248 allocator_type& allocator() {
return header_m.get().alloc_free_tail_m.first(); }
249 const allocator_type& allocator()
const {
return header_m.
get().alloc_free_tail_m.first(); }
250 node_base_t& free_tail() {
return header_m.
get().alloc_free_tail_m.second(); }
251 const node_base_t& free_tail()
const {
return header_m.
get().alloc_free_tail_m.second(); }
252 node_base_t& used_tail() {
return header_m.
get().used_tail_m; }
253 const node_base_t& used_tail()
const {
return header_m.
get().used_tail_m; }
254 std::size_t& capacity() {
return header_m.
get().capacity_m; }
255 const std::size_t& capacity()
const {
return header_m.
get().capacity_m; }
256 std::size_t&
size() {
return header_m.
get().size_m; }
257 const std::size_t&
size()
const {
return header_m.
get().size_m; }
260 typedef node_t* node_ptr;
262 typedef boost::compressed_pair<
263 hasher, boost::compressed_pair<key_equal, boost::compressed_pair<key_transform, header_t*>>>
268 typedef header_t* header_pointer;
270 const header_pointer& header()
const {
return data_m.second().second().second(); }
271 header_pointer& header() {
return data_m.second().second().second(); }
288 data_m.second().first() = eq;
289 data_m.second().second().first() = kf;
293 template <
typename I>
301 insert(init.begin(), init.end());
304 template <
typename I>
310 data_m.second().first() = eq;
311 data_m.second().second().first() = kf;
361 return iterator(header() ?
const_cast<node_t*
>(header()->used_tail().address()) : 0);
371 iterator next(boost::next(location));
374 if ((location.state() == std::size_t(state_home)) && (next !=
end()) &&
375 (next.state() == std::size_t(state_misplaced))) {
376 swap(*next, *location);
417 if (node.state() != std::size_t(state_home))
420 return find(node, last, key);
430 return std::make_pair(result, result);
431 return std::make_pair(result, boost::next(result));
442 return std::make_pair(result, result);
443 return std::make_pair(result, boost::next(result));
449 return std::size_t(
find(key, hash) !=
end());
452 template <
typename I>
454 while (first != last) {
460 template <
typename I>
462 while (first != last) {
463 insert(std::move(*first));
484 switch (node.state()) {
487 if (found !=
end()) {
488 return std::make_pair(found,
false);
492 insert_raw(free, std::move(x), state_misplaced);
496 case state_misplaced: {
498 insert_raw(free, std::move(*node), state_misplaced);
508 insert_raw(node, std::move(x), state_home);
512 header()->size() += 1;
513 return std::make_pair(node,
true);
523 alloc.deallocate(
reinterpret_cast<char*
>(header()), 0);
534 if (iter == y.
end() || !(*first == *iter))
541 typedef typename allocator_type::template rebind<char>::other raw_allocator;
544 void allocate(
const allocator_type& a, size_type n) {
547 static const std::size_t prime_table[] = {
548 3UL, 7UL, 17UL, 37UL, 79UL, 163UL,
549 331UL, 673UL, 1361UL, 2729UL, 5471UL, 10949UL,
550 21911UL, 43853UL, 87719UL, 175447UL, 350899UL, 701819UL,
551 1403641UL, 2807303UL, 5614657UL, 11229331UL, 22458671UL, 44917381UL,
552 89834777UL, 179669557UL, 359339171UL, 718678369UL, 1437356741UL, 2874713497UL,
555 assert(!header() &&
"WARNING (sparent@adobe.com) : About to write over allocated header.");
557 if (n == 0 && a == allocator_type())
562 raw_allocator alloc(a);
564 header() =
reinterpret_cast<header_t*
>(
565 alloc.allocate(
sizeof(header_t) -
sizeof(node_t) +
sizeof(node_t) * n));
566 header()->capacity() = n;
567 header()->size() = 0;
572 node_t* prior = header()->free_tail().address();
573 for (node_ptr first(&header()->storage_m[0]), last(&header()->storage_m[0] + n);
574 first != last; ++first) {
575 set_next_raw(*prior, *first);
579 set_next_raw(*prior, header()->free_tail());
584 iterator end_() {
return iterator(header()->used_tail().address()); }
587 size_type capacity_()
const {
return header()->capacity(); }
590 iterator bucket_(std::size_t hash) {
591 return iterator(&header()->storage_m[0] + hash % capacity_());
595 iterator
find(iterator f, iterator l,
const key_type& key) {
597 if (key_eq()(key, key_function()(*f)))
600 }
while ((f != l) && (f.state() != std::size_t(state_home)));
606 static void insert_raw(iterator location, value_type x, std::size_t state) {
608 location.set_state(state);
609 unsafe::skip_node(location);
613 void erase_raw(iterator location) {
615 location.set_state(state_free);
616 unsafe::splice_node_range(end_free(), location, location);
619 iterator begin_free() {
return iterator(header() ? header()->free_tail().next() : 0); }
620 iterator end_free() {
return iterator(header() ? header()->free_tail().address() : 0); }
641template <
typename Key,
typename T,
typename Hash,
typename Pred,
typename A>
651 template <
typename I>
654 closed_hash_map(std::initializer_list<typename set_type::value_type> init) : set_type(init) {}
664 swap(
static_cast<set_type&
>(x),
static_cast<set_type&
>(y));
669 return static_cast<const set_type&
>(x) ==
static_cast<const set_type&
>(y);
680#ifndef ADOBE_CLOSED_HASH_MAP_INDEX
681#define ADOBE_CLOSED_HASH_MAP_INDEX 1
684#if ADOBE_CLOSED_HASH_MAP_INDEX
686 mapped_type& operator[](
const Key& x) {
687 typename set_type::iterator i = this->find(x);
688 if (i == this->end()) {
689 return this->insert(std::make_pair(x, mapped_type())).first->second;
699static_assert(
sizeof(closed_hash_set<int>) ==
sizeof(
void*));
702#ifndef ADOBE_NO_DOCUMENTATION
A hash based associative container.
closed_hash_map(const closed_hash_map &x)
closed_hash_map & operator=(closed_hash_map x)
friend bool operator!=(const closed_hash_map &x, const closed_hash_map &y)
closed_hash_map(std::initializer_list< typename set_type::value_type > init)
closed_hash_map(closed_hash_map &&x) noexcept
closed_hash_map(I f, I l)
friend bool operator==(const closed_hash_map &x, const closed_hash_map &y)
friend void swap(closed_hash_map &x, closed_hash_map &y)
A hash based associative container.
const_reverse_iterator rend() const
iterator erase(iterator location)
const value_type * const_pointer
void move_insert(I first, I last)
iterator find(const key_type &key, std::size_t hash)
const_iterator begin() const
closed_hash_set(size_type n, const hasher &hf, const key_equal &eq=key_equal(), const key_transform &kf=key_transform(), const allocator_type &a=allocator_type())
std::pair< iterator, bool > insert(value_type x)
KeyTransform key_transform
closed_hash_set(I f, I l)
std::reverse_iterator< const_iterator > const_reverse_iterator
std::pair< const_iterator, const_iterator > equal_range(const key_type &key) const
std::size_t erase(const key_type &key)
void reserve(size_type n)
std::pair< iterator, bool > insert(value_type x, std::size_t hash)
std::pair< const_iterator, const_iterator > equal_range(const key_type &key, size_t hash) const
allocator_type get_allocator() const
const_iterator find(const key_type &key, std::size_t hash) const
hasher hash_function() const
key_transform key_function() const
std::size_t count(const key_type &key, std::size_t hash) const
closed_hash_set(closed_hash_set &&x) noexcept
friend bool operator==(const closed_hash_set &x, const closed_hash_set &y)
std::reverse_iterator< iterator > reverse_iterator
size_type max_size() const
std::size_t count(const key_type &key) const
implementation::closed_hash_iterator< closed_hash_set, const value_type > const_iterator
iterator find(const key_type &key)
iterator insert(iterator, value_type x)
std::pair< iterator, iterator > equal_range(const key_type &key, std::size_t hash)
std::remove_reference_t< adobe::invoke_result_t< KeyTransform, T > > key_type
implementation::closed_hash_iterator< closed_hash_set, value_type > iterator
void insert(I first, I last)
closed_hash_set & operator=(closed_hash_set x)
friend void swap(closed_hash_set &x, closed_hash_set &y)
closed_hash_set(std::initializer_list< value_type > init)
closed_hash_set(const closed_hash_set &x)
const_iterator end() const
reverse_iterator rbegin()
size_type capacity() const
std::pair< iterator, iterator > equal_range(const key_type &key)
std::ptrdiff_t difference_type
closed_hash_set(size_type n)
const_reverse_iterator rbegin() const
const_iterator find(const key_type &key) const
closed_hash_set(I f, I l, size_type n, const hasher &hf=hasher(), const key_equal &eq=key_equal(), const key_transform &kf=key_transform(), const allocator_type &a=allocator_type())
const value_type & const_reference
void skip_node(I location)
void splice_node_range(I location, I first, I last)
T & remove_const(const T &x)
boost::range_iterator< InputRange >::type find(InputRange &range, const T &value)
find implementation
boost::range_size< Selection >::type size(const Selection &x)
I lower_bound(I f, I l, const T &x)
T * construct_at(T *p, Args &&... args)
void swap(adobe::extents_t::slice_t &x, adobe::extents_t::slice_t &y) BOOST_NOEXCEPT