From fdd7d6bbfbbd0b8249215f67d93474b905d9893a Mon Sep 17 00:00:00 2001 From: Daniel James Date: Wed, 19 Dec 2007 23:23:42 +0000 Subject: [PATCH] Remove 'local_iterator_base'. Merged revisions 42153-42156 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/dev ........ r42153 | danieljames | 2007-12-18 22:51:31 +0000 (Tue, 18 Dec 2007) | 2 lines Remove 'local_iterator_base'. It isn't really needed. ........ r42155 | danieljames | 2007-12-18 22:58:12 +0000 (Tue, 18 Dec 2007) | 1 line Add a helper function for creating null pointers. ........ r42156 | danieljames | 2007-12-18 23:14:49 +0000 (Tue, 18 Dec 2007) | 3 lines Check that I'm using link_ptr & bucket_ptr correctly (they should be distinct types with an explicit conversion from bucket_ptr to link_ptr). ........ [SVN r42189] --- include/boost/unordered/detail/allocator.hpp | 6 + .../unordered/detail/hash_table_impl.hpp | 334 ++++++++---------- 2 files changed, 160 insertions(+), 180 deletions(-) diff --git a/include/boost/unordered/detail/allocator.hpp b/include/boost/unordered/detail/allocator.hpp index 5e421ea6..671b130c 100644 --- a/include/boost/unordered/detail/allocator.hpp +++ b/include/boost/unordered/detail/allocator.hpp @@ -42,6 +42,9 @@ namespace boost { #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) template inline void reset(T& x) { x = T(); } + + template + inline Ptr null_ptr() { return Ptr(); } #else template inline void reset_impl(T& x, ...) { x = T(); } @@ -49,6 +52,9 @@ namespace boost { inline void reset_impl(T*& x, int) { x = 0; } template inline void reset(T& x) { reset_impl(x); } + + template + inline Ptr null_ptr() { Ptr x; reset(x); return x; } #endif // Work around for Microsoft's ETI bug. diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 7795527d..b9d698ed 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -53,8 +53,28 @@ namespace boost { typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type node_ptr; typedef BOOST_DEDUCED_TYPENAME allocator_pointer::type bucket_ptr; typedef BOOST_DEDUCED_TYPENAME allocator_reference::type reference; - typedef bucket_ptr link_ptr; + typedef BOOST_DEDUCED_TYPENAME allocator_reference::type bucket_reference; +#if 1 + typedef bucket_ptr link_ptr; +#else + // This alternative version of link_ptr is used to check that the + // implementation is type safe wrt bucket_ptr and link_ptr. + // + // It's a sort of strict typedef. + + struct link_ptr { + link_ptr() : ptr_() { BOOST_HASH_MSVC_RESET_PTR(ptr_); } + explicit link_ptr(bucket_ptr p) : ptr_(p) {} + bucket_reference operator*() const { return *ptr_; } + bucket* operator->() const { return &*ptr_; } + operator bool() const { return ptr_; } + bool operator==(link_ptr const& x) const { return ptr_ == x.ptr_; } + bool operator!=(link_ptr const& x) const { return ptr_ != x.ptr_; } + private: + bucket_ptr ptr_; + }; +#endif // Hash Bucket // // all no throw @@ -256,31 +276,31 @@ namespace boost { return static_cast(*p).value_; } - class local_iterator_base + class iterator_base { public: + bucket_ptr bucket_; link_ptr node_; - local_iterator_base() - : node_() + iterator_base() + : bucket_(), node_() { + BOOST_HASH_MSVC_RESET_PTR(bucket_); BOOST_HASH_MSVC_RESET_PTR(node_); } - explicit local_iterator_base(link_ptr n) - : node_(n) {} + explicit iterator_base(bucket_ptr b) + : bucket_(b), node_(b->next_) {} - bool not_finished() const - { - return node_ ? true : false; - } + iterator_base(bucket_ptr b, link_ptr n) + : bucket_(b), node_(n) {} - bool operator==(local_iterator_base const& x) const + bool operator==(iterator_base const& x) const { return node_ == x.node_; } - bool operator!=(local_iterator_base const& x) const + bool operator!=(iterator_base const& x) const { return node_ != x.node_; } @@ -290,59 +310,14 @@ namespace boost { return get_value(node_); } - void increment() - { - BOOST_ASSERT(node_); - node_ = node_->next_; - } - - void next_group() - { - node_ = BOOST_UNORDERED_TABLE_DATA::next_group(node_); - } - }; - - class iterator_base - { - public: - bucket_ptr bucket_; - local_iterator_base local_; - - iterator_base() - : bucket_(), local_() {} - - explicit iterator_base(bucket_ptr b) - : bucket_(b), local_(b->next_) {} - - iterator_base(bucket_ptr b, link_ptr n) - : bucket_(b), local_(n) {} - - iterator_base(bucket_ptr b, local_iterator_base const& it) - : bucket_(b), local_(it) {} - - bool operator==(iterator_base const& x) const - { - return local_ == x.local_; - } - - bool operator!=(iterator_base const& x) const - { - return local_ != x.local_; - } - - reference operator*() const - { - return *local_; - } - void increment() { BOOST_ASSERT(bucket_); - local_.increment(); + node_ = node_->next_; - while (!local_.node_) { + while (!node_) { ++bucket_; - local_ = local_iterator_base(bucket_->next_); + node_ = bucket_->next_; } } }; @@ -462,41 +437,40 @@ namespace boost { return iterator_base(buckets_ + bucket_count_); } - local_iterator_base begin(size_type n) const + link_ptr begin(size_type n) const { - return local_iterator_base(buckets_[n].next_); + return buckets_[n].next_; } - local_iterator_base end(size_type) const + link_ptr end(size_type) const { - return local_iterator_base(); + return unordered_detail::null_ptr(); } - local_iterator_base begin(bucket_ptr b) const + link_ptr begin(bucket_ptr b) const { - return local_iterator_base(b->next_); + return b->next_; } // Bucket Size // no throw - size_type node_count(local_iterator_base it) const + size_type node_count(link_ptr it) const { size_type count = 0; - while(it.not_finished()) { + while(BOOST_HASH_BORLAND_BOOL(it)) { ++count; - it.increment(); + it = it->next_; } return count; } - size_type node_count(local_iterator_base it1, - local_iterator_base it2) const + size_type node_count(link_ptr it1, link_ptr it2) const { size_type count = 0; while(it1 != it2) { ++count; - it1.increment(); + it1 = it1->next_; } return count; } @@ -507,10 +481,9 @@ namespace boost { } #if BOOST_UNORDERED_HASH_EQUIVALENT - size_type group_count(local_iterator_base first_node) const + size_type group_count(link_ptr it) const { size_type count = 0; - link_ptr it = first_node.node_; link_ptr first = it; do { ++count; @@ -519,7 +492,7 @@ namespace boost { return count; } #else - size_type group_count(local_iterator_base) const + size_type group_count(link_ptr) const { return 1; } @@ -534,7 +507,7 @@ namespace boost { #if BOOST_UNORDERED_HASH_EQUIVALENT static link_ptr* get_for_erase(iterator_base r) { - link_ptr n = r.local_.node_; + link_ptr n = r.node_; // If the element isn't the first in its group, then // the link to it will be found in the previous element @@ -551,7 +524,7 @@ namespace boost { #else static link_ptr* get_for_erase(iterator_base r) { - link_ptr n = r.local_.node_; + link_ptr n = r.node_; link_ptr* it = &r.bucket_->next_; while(*it != n) it = &(*it)->next_; return it; @@ -566,10 +539,10 @@ namespace boost { // no throw #if BOOST_UNORDERED_HASH_EQUIVALENT - void link_node(link_ptr n, local_iterator_base pos) + void link_node(link_ptr n, link_ptr pos) { node& node_ref = get_node(n); - node& pos_ref = get_node(pos.node_); + node& pos_ref = get_node(pos); node_ref.next_ = pos_ref.group_prev_->next_; node_ref.group_prev_ = pos_ref.group_prev_; pos_ref.group_prev_->next_ = n; @@ -577,7 +550,7 @@ namespace boost { ++size_; } - void link_node(link_ptr n, bucket_ptr base) + void link_node_in_bucket(link_ptr n, bucket_ptr base) { node& node_ref = get_node(n); node_ref.next_ = base->next_; @@ -597,7 +570,7 @@ namespace boost { if(base < cached_begin_bucket_) cached_begin_bucket_ = base; } #else - void link_node(link_ptr n, bucket_ptr base) + void link_node_in_bucket(link_ptr n, bucket_ptr base) { n->next_ = base->next_; base->next_ = n; @@ -607,7 +580,7 @@ namespace boost { void link_group(link_ptr n, bucket_ptr base, size_type) { - link_node(n, base); + link_node_in_bucket(n, base); } #endif @@ -615,7 +588,7 @@ namespace boost { void unlink_node(iterator_base it) { link_ptr* pos = get_for_erase(it); - node* n = &get_node(it.local_.node_); + node* n = &get_node(it.node_); link_ptr next = n->next_; if(n->group_prev_ == *pos) { @@ -644,7 +617,7 @@ namespace boost { size_type unlink_group(link_ptr* pos) { - size_type count = group_count(local_iterator_base(*pos)); + size_type count = group_count(*pos); size_ -= count; link_ptr last = last_in_group(*pos); *pos = last->next_; @@ -671,31 +644,28 @@ namespace boost { link_ptr* it = get_for_erase(n); split_group(*it); unordered_detail::reset(*it); - size_ -= node_count(n.local_); + size_ -= node_count(n.node_); } void unlink_nodes(iterator_base begin, iterator_base end) { BOOST_ASSERT(begin.bucket_ == end.bucket_); - local_iterator_base local_end = end.local_; - - size_ -= node_count(begin.local_, local_end); + size_ -= node_count(begin.node_, end.node_); link_ptr* it = get_for_erase(begin); - split_group(*it, local_end.node_); - *it = local_end.node_; + split_group(*it, end.node_); + *it = end.node_; } void unlink_nodes(bucket_ptr base, iterator_base end) { BOOST_ASSERT(base == end.bucket_); - local_iterator_base local_end = end.local_; - split_group(local_end.node_); + split_group(end.node_); link_ptr ptr(base->next_); - base->next_ = local_end.node_; + base->next_ = end.node_; - size_ -= node_count(local_iterator_base(ptr), local_end); + size_ -= node_count(ptr, end.node_); } #if BOOST_UNORDERED_HASH_EQUIVALENT @@ -707,7 +677,7 @@ namespace boost { // If split is at the beginning of the group then there's // nothing to split. if(prev_in_group(split)->next_ != split) - return link_ptr(); + return unordered_detail::null_ptr(); // Find the start of the group. link_ptr start = split; @@ -763,7 +733,7 @@ namespace boost { link_ptr n = construct_node(v); // Rest is no throw - link_node(n, base); + link_node_in_bucket(n, base); return iterator_base(base, n); } @@ -774,39 +744,38 @@ namespace boost { link_ptr n = construct_node(v); // Rest is no throw - link_node(n, position.local_); + link_node(n, position.node_); return iterator_base(position.bucket_, n); } iterator_base create_node(value_type const& v, - bucket_ptr base, local_iterator_base position) + bucket_ptr base, link_ptr position) { // throws, strong exception-safety: link_ptr n = construct_node(v); // Rest is no throw - if(position.not_finished()) + if(BOOST_HASH_BORLAND_BOOL(position)) link_node(n, position); else - link_node(n, base); + link_node_in_bucket(n, base); return iterator_base(base, n); } #endif #if BOOST_UNORDERED_HASH_EQUIVALENT - void copy_group(local_iterator_base it, bucket_ptr dst) + void copy_group(link_ptr it, bucket_ptr dst) { - local_iterator_base end = it; - end.next_group(); - iterator_base pos = create_node(*it, dst); - for(it.increment(); it != end; it.increment()) - create_node(*it, pos); + link_ptr end = next_group(it); + iterator_base pos = create_node(get_value(it), dst); + for(it = it->next_; it != end; it = it->next_) + create_node(get_value(it), pos); } #else - void copy_group(local_iterator_base it, bucket_ptr dst) + void copy_group(link_ptr it, bucket_ptr dst) { - create_node(*it, dst); + create_node(get_value(it), dst); } #endif @@ -884,7 +853,7 @@ namespace boost { iterator_base next = r; next.increment(); unlink_node(r); - allocators_.destroy(r.local_.node_); + allocators_.destroy(r.node_); // r has been invalidated but its bucket is still valid recompute_begin_bucket(r.bucket_, next.bucket_); return next; @@ -898,7 +867,7 @@ namespace boost { if (r1.bucket_ == r2.bucket_) { unlink_nodes(r1, r2); - delete_nodes(r1.local_.node_, r2.local_.node_); + delete_nodes(r1.node_, r2.node_); // No need to call recompute_begin_bucket because // the nodes are only deleted from one bucket, which @@ -909,17 +878,17 @@ namespace boost { BOOST_ASSERT(r1.bucket_ < r2.bucket_); unlink_nodes(r1); - delete_to_bucket_end(r1.local_.node_); + delete_to_bucket_end(r1.node_); for(bucket_ptr i = r1.bucket_ + 1; i != r2.bucket_; ++i) { - size_ -= node_count(local_iterator_base(i->next_)); + size_ -= node_count(i->next_); clear_bucket(i); } if(r2 != end()) { link_ptr first = r2.bucket_->next_; unlink_nodes(r2.bucket_, r2); - delete_nodes(first, r2.local_.node_); + delete_nodes(first, r2.node_); } // r1 has been invalidated but its bucket is still @@ -1019,7 +988,6 @@ namespace boost { // iterators - typedef BOOST_DEDUCED_TYPENAME data::local_iterator_base local_iterator_base; typedef BOOST_DEDUCED_TYPENAME data::iterator_base iterator_base; private: @@ -1489,11 +1457,11 @@ namespace boost { // no throw: for(bucket_ptr i = src.cached_begin_bucket_; i != end; ++i) { // no throw: - for(local_iterator_base it = src.begin(i); - it.not_finished(); it.next_group()) { + for(link_ptr it = src.begin(i); + BOOST_HASH_BORLAND_BOOL(it); it = data::next_group(it)) { // hash function can throw. bucket_ptr dst_bucket = dst.buckets_ + - dst.index_from_hash(hf(extract_key(*it))); + dst.index_from_hash(hf(extract_key(data::get_value(it)))); // throws, strong dst.copy_group(it, dst_bucket); } @@ -1519,7 +1487,7 @@ namespace boost { size_type hash_value = hash_function()(k); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - local_iterator_base position = find_iterator(bucket, k); + link_ptr position = find_iterator(bucket, k); // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). @@ -1535,12 +1503,12 @@ namespace boost { link_ptr n = a.release(); - // I'm relying on local_iterator_base not being invalidated by + // I'm relying on link_ptr not being invalidated by // the rehash here. - if(position.not_finished()) + if(BOOST_HASH_BORLAND_BOOL(position)) this->link_node(n, position); else - this->link_node(n, bucket); + this->link_node_in_bucket(n, bucket); return iterator_base(bucket, n); } @@ -1561,9 +1529,9 @@ namespace boost { // Find the first node in the group - so that the node // will be inserted at the end of the group. - local_iterator_base start(it.local_); - while(this->prev_in_group(start.node_)->next_ == start.node_) - start.node_ = this->prev_in_group(start.node_); + link_ptr start(it.node_); + while(this->prev_in_group(start)->next_ == start) + start = this->prev_in_group(start); // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). @@ -1607,12 +1575,12 @@ namespace boost { key_type const& k = extract_key(a.get()->value_); bucket_ptr bucket = get_bucket(k); - local_iterator_base position = find_iterator(bucket, k); + link_ptr position = find_iterator(bucket, k); - if(position.not_finished()) + if(BOOST_HASH_BORLAND_BOOL(position)) this->link_node(a.release(), position); else - this->link_node(a.release(), bucket); + this->link_node_in_bucket(a.release(), bucket); } } } @@ -1650,10 +1618,10 @@ namespace boost { size_type hash_value = hash_function()(k); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - local_iterator_base pos = find_iterator(bucket, k); + link_ptr pos = find_iterator(bucket, k); - if (pos.not_finished()) - return *pos; + if (BOOST_HASH_BORLAND_BOOL(pos)) + return data::get_value(pos); else { // Side effects only in this block. @@ -1671,9 +1639,9 @@ namespace boost { // Nothing after this point can throw. link_ptr n = a.release(); - this->link_node(n, bucket); + this->link_node_in_bucket(n, bucket); - return *local_iterator_base(n); + return data::get_value(n); } } @@ -1687,9 +1655,9 @@ namespace boost { key_type const& k = extract_key(v); size_type hash_value = hash_function()(k); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - local_iterator_base pos = find_iterator(bucket, k); + link_ptr pos = find_iterator(bucket, k); - if (pos.not_finished()) { + if (BOOST_HASH_BORLAND_BOOL(pos)) { // Found an existing key, return it (no throw). return std::pair( iterator_base(bucket, pos), false); @@ -1711,7 +1679,7 @@ namespace boost { // Nothing after this point can throw. link_ptr n = a.release(); - this->link_node(n, bucket); + this->link_node_in_bucket(n, bucket); return std::pair( iterator_base(bucket, n), true); @@ -1764,9 +1732,9 @@ namespace boost { size_type hash_value = hash_function()(extract_key(*i)); bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); - local_iterator_base pos = find_iterator(bucket, extract_key(*i)); + link_ptr pos = find_iterator(bucket, extract_key(*i)); - if (!pos.not_finished()) { + if (!BOOST_HASH_BORLAND_BOOL(pos)) { // Doesn't already exist, add to bucket. // Side effects only in this block. @@ -1784,7 +1752,7 @@ namespace boost { } // Nothing after this point can throw. - this->link_node(a.release(), bucket); + this->link_node_in_bucket(a.release(), bucket); } } } @@ -1821,8 +1789,8 @@ namespace boost { // strong exception safety, no side effects size_type count(key_type const& k) const { - local_iterator_base it = find_iterator(k); // throws, strong - return it.not_finished() ? this->group_count(it) : 0; + link_ptr it = find_iterator(k); // throws, strong + return BOOST_HASH_BORLAND_BOOL(it) ? this->group_count(it) : 0; } // find @@ -1831,9 +1799,9 @@ namespace boost { iterator_base find(key_type const& k) const { bucket_ptr bucket = get_bucket(k); - local_iterator_base it = find_iterator(bucket, k); + link_ptr it = find_iterator(bucket, k); - if (it.not_finished()) + if (BOOST_HASH_BORLAND_BOOL(it)) return iterator_base(bucket, it); else return this->end(); @@ -1842,10 +1810,10 @@ namespace boost { value_type& at(key_type const& k) const { bucket_ptr bucket = get_bucket(k); - local_iterator_base it = find_iterator(bucket, k); + link_ptr it = find_iterator(bucket, k); - if (it.not_finished()) - return *it; + if (BOOST_HASH_BORLAND_BOOL(it)) + return data::get_value(it); else throw std::out_of_range("Unable to find key in unordered_map."); } @@ -1856,10 +1824,10 @@ namespace boost { std::pair equal_range(key_type const& k) const { bucket_ptr bucket = get_bucket(k); - local_iterator_base it = find_iterator(bucket, k); - if (it.not_finished()) { + link_ptr it = find_iterator(bucket, k); + if (BOOST_HASH_BORLAND_BOOL(it)) { iterator_base first(iterator_base(bucket, it)); - iterator_base second(iterator_base(bucket, this->last_in_group(it.node_))); + iterator_base second(iterator_base(bucket, this->last_in_group(it))); second.increment(); return std::pair(first, second); } @@ -1878,18 +1846,18 @@ namespace boost { } // strong exception safety, no side effects - local_iterator_base find_iterator(key_type const& k) const + link_ptr find_iterator(key_type const& k) const { return find_iterator(get_bucket(k), k); } // strong exception safety, no side effects - local_iterator_base find_iterator(bucket_ptr bucket, + link_ptr find_iterator(bucket_ptr bucket, key_type const& k) const { - local_iterator_base it = this->begin(bucket); - while (it.not_finished() && !equal(k, *it)) - it.next_group(); + link_ptr it = this->begin(bucket); + while (BOOST_HASH_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) + it = data::next_group(it); return it; } @@ -1898,8 +1866,8 @@ namespace boost { link_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const { link_ptr* it = &bucket->next_; - while(BOOST_HASH_BORLAND_BOOL(*it) && !equal(k, this->get_value(*it))) - it = &this->next_group(*it); + while(BOOST_HASH_BORLAND_BOOL(*it) && !equal(k, data::get_value(*it))) + it = &data::next_group(*it); return it; } @@ -1930,24 +1898,27 @@ namespace boost { typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; private: - typedef BOOST_DEDUCED_TYPENAME BOOST_UNORDERED_TABLE_DATA::local_iterator_base base; + typedef BOOST_UNORDERED_TABLE_DATA data; + typedef BOOST_DEDUCED_TYPENAME data::link_ptr ptr; typedef BOOST_UNORDERED_CONST_LOCAL_ITERATOR const_local_iterator; friend class BOOST_UNORDERED_CONST_LOCAL_ITERATOR; - base base_; + ptr ptr_; public: - BOOST_UNORDERED_LOCAL_ITERATOR() : base_() {} - explicit BOOST_UNORDERED_LOCAL_ITERATOR(base x) : base_(x) {} + BOOST_UNORDERED_LOCAL_ITERATOR() : ptr_() { + BOOST_HASH_MSVC_RESET_PTR(ptr_); + } + explicit BOOST_UNORDERED_LOCAL_ITERATOR(ptr x) : ptr_(x) {} BOOST_DEDUCED_TYPENAME allocator_reference::type operator*() const - { return *base_; } - value_type* operator->() const { return &*base_; } - BOOST_UNORDERED_LOCAL_ITERATOR& operator++() { base_.increment(); return *this; } - BOOST_UNORDERED_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_LOCAL_ITERATOR tmp(base_); base_.increment(); return tmp; } - bool operator==(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return base_ == x.base_; } - bool operator==(const_local_iterator x) const { return base_ == x.base_; } - bool operator!=(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return base_ != x.base_; } - bool operator!=(const_local_iterator x) const { return base_ != x.base_; } + { return data::get_value(ptr_); } + value_type* operator->() const { return &data::get_value(ptr_); } + BOOST_UNORDERED_LOCAL_ITERATOR& operator++() { ptr_ = ptr_->next_; return *this; } + BOOST_UNORDERED_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_LOCAL_ITERATOR tmp(ptr_); ptr_ = ptr_->next_; return tmp; } + bool operator==(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return ptr_ == x.ptr_; } + bool operator==(const_local_iterator x) const { return ptr_ == x.ptr_; } + bool operator!=(BOOST_UNORDERED_LOCAL_ITERATOR x) const { return ptr_ != x.ptr_; } + bool operator!=(const_local_iterator x) const { return ptr_ != x.ptr_; } }; template @@ -1963,24 +1934,27 @@ namespace boost { typedef BOOST_DEDUCED_TYPENAME allocator_value_type::type value_type; private: - typedef BOOST_DEDUCED_TYPENAME BOOST_UNORDERED_TABLE_DATA::local_iterator_base base; + typedef BOOST_UNORDERED_TABLE_DATA data; + typedef BOOST_DEDUCED_TYPENAME data::link_ptr ptr; typedef BOOST_UNORDERED_LOCAL_ITERATOR local_iterator; friend class BOOST_UNORDERED_LOCAL_ITERATOR; - base base_; + ptr ptr_; public: - BOOST_UNORDERED_CONST_LOCAL_ITERATOR() : base_() {} - explicit BOOST_UNORDERED_CONST_LOCAL_ITERATOR(base x) : base_(x) {} - BOOST_UNORDERED_CONST_LOCAL_ITERATOR(local_iterator x) : base_(x.base_) {} + BOOST_UNORDERED_CONST_LOCAL_ITERATOR() : ptr_() { + BOOST_HASH_MSVC_RESET_PTR(ptr_); + } + explicit BOOST_UNORDERED_CONST_LOCAL_ITERATOR(ptr x) : ptr_(x) {} + BOOST_UNORDERED_CONST_LOCAL_ITERATOR(local_iterator x) : ptr_(x.ptr_) {} BOOST_DEDUCED_TYPENAME allocator_const_reference::type - operator*() const { return *base_; } - value_type const* operator->() const { return &*base_; } - BOOST_UNORDERED_CONST_LOCAL_ITERATOR& operator++() { base_.increment(); return *this; } - BOOST_UNORDERED_CONST_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_CONST_LOCAL_ITERATOR tmp(base_); base_.increment(); return tmp; } - bool operator==(local_iterator x) const { return base_ == x.base_; } - bool operator==(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return base_ == x.base_; } - bool operator!=(local_iterator x) const { return base_ != x.base_; } - bool operator!=(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return base_ != x.base_; } + operator*() const { return data::get_value(ptr_); } + value_type const* operator->() const { return &data::get_value(ptr_); } + BOOST_UNORDERED_CONST_LOCAL_ITERATOR& operator++() { ptr_ = ptr_->next_; return *this; } + BOOST_UNORDERED_CONST_LOCAL_ITERATOR operator++(int) { BOOST_UNORDERED_CONST_LOCAL_ITERATOR tmp(ptr_); ptr_ = ptr_->next_; return tmp; } + bool operator==(local_iterator x) const { return ptr_ == x.ptr_; } + bool operator==(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return ptr_ == x.ptr_; } + bool operator!=(local_iterator x) const { return ptr_ != x.ptr_; } + bool operator!=(BOOST_UNORDERED_CONST_LOCAL_ITERATOR x) const { return ptr_ != x.ptr_; } }; // iterators