// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard. // Copyright (C) 2005-2009 Daniel James // 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) // This contains the basic data structure, apart from the actual values. There's // no construction or deconstruction here. So this only depends on the pointer // type. #ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED #define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED #include #include #include #include #if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582) #define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) #else #define BOOST_UNORDERED_BORLAND_BOOL(x) x #endif namespace boost { namespace unordered_detail { template inline BucketPtr& next_node(BucketPtr ptr) { return ptr->next_; } template inline std::size_t node_count(BucketPtr ptr, BucketPtr end) { std::size_t count = 0; while(ptr != end) { ++count; ptr = next_node(ptr); } return count; } //////////////////////////////////////////////////////////////////////////// // ungrouped node implementation template inline BOOST_DEDUCED_TYPENAME ungrouped_node_base::node_ptr& ungrouped_node_base::next_group(node_ptr ptr) { return next_node(ptr); } template inline std::size_t ungrouped_node_base::group_count(node_ptr) { return 1; } template inline void ungrouped_node_base::add_to_bucket(node_ptr n, bucket& b) { next_node(n) = b.next_; b.next_ = n; } template inline void ungrouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) { next_node(n) = b.next_; b.next_ = n; } template inline void ungrouped_node_base::add_after_node(node_ptr n, node_ptr position) { next_node(n) = next_node(position); next_node(position) = position; } template void ungrouped_node_base::unlink_node(bucket& b, node_ptr node) { unlink_nodes(b, node, next_node(node)); } template void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) { node_ptr* pos = &b.next_; while(*pos != begin) pos = &next_node(*pos); *pos = end; } template void ungrouped_node_base::unlink_nodes(bucket& b, node_ptr end) { b.next_ = end; } template inline void ungrouped_node_base::unlink_group(node_ptr* b) { *b = next_node(*b); } //////////////////////////////////////////////////////////////////////////// // grouped node implementation template inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& grouped_node_base::group_prev(node_ptr ptr) { return get(ptr).group_prev_; } template inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr& grouped_node_base::next_group(node_ptr ptr) { return next_node(group_prev(ptr)); } template inline std::size_t grouped_node_base::group_count(node_ptr ptr) { node_ptr start = ptr; std::size_t size = 0; do { ++size; ptr = group_prev(ptr); } while(ptr != start); return size; } template inline void grouped_node_base::add_to_bucket(node_ptr n, bucket& b) { next_node(n) = b.next_; group_prev(n) = n; b.next_ = n; } template inline void grouped_node_base::add_group_to_bucket(node_ptr n, bucket& b) { next_group(n) = b.next_; b.next_ = n; } template inline void grouped_node_base::add_after_node(node_ptr n, node_ptr position) { next_node(n) = next_group(position); group_prev(n) = group_prev(position); next_group(position) = n; group_prev(position) = n; } // Break a ciruclar list into two, with split as the beginning // of the second group (if split is at the beginning then don't // split). template inline BOOST_DEDUCED_TYPENAME grouped_node_base::node_ptr grouped_node_base::split_group(node_ptr split) { // If split is at the beginning of the group then there's // nothing to split. if(next_node(group_prev(split)) != split) return split; // Find the start of the group. node_ptr start = split; do { start = group_prev(start); } while(next_node(group_prev(start)) == start); node_ptr last = group_prev(start); group_prev(start) = group_prev(split); group_prev(split) = last; return start; } template void grouped_node_base::unlink_node(bucket& b, node_ptr node) { node_ptr next = next_node(node); node_ptr* pos = &next_node(group_prev(node)); if(*pos != node) { // The node is at the beginning of a group. // Find the previous node pointer: pos = &b.next_; while(*pos != node) pos = &next_group(*pos); // Remove from group if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) group_prev(next) = group_prev(node); } else if(BOOST_UNORDERED_BORLAND_BOOL(next) && group_prev(next) == node) { // The deleted node is not at the end of the group, so // change the link from the next node. group_prev(next) = group_prev(node); } else { // The deleted node is at the end of the group, so the // first node in the group is pointing to it. // Find that to change its pointer. node_ptr x = group_prev(node); while(group_prev(x) != node) { x = group_prev(x); } group_prev(x) = group_prev(node); } *pos = next; } template void grouped_node_base::unlink_nodes(bucket& b, node_ptr begin, node_ptr end) { node_ptr* pos = &next_node(group_prev(begin)); if(*pos != begin) { // The node is at the beginning of a group. // Find the previous node pointer: pos = &b.next_; while(*pos != begin) pos = &next_group(*pos); // Remove from group if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end); } else { node_ptr group1 = split_group(begin); if(BOOST_UNORDERED_BORLAND_BOOL(end)) { node_ptr group2 = split_group(end); if(begin == group2) { node_ptr end1 = group_prev(group1); node_ptr end2 = group_prev(group2); group_prev(group1) = end2; group_prev(group2) = end1; } } } *pos = end; } template void grouped_node_base::unlink_nodes(bucket& b, node_ptr end) { split_group(end); b.next_ = end; } template inline void grouped_node_base::unlink_group(node_ptr* b) { *b = next_group(*b); } }} #endif