From 6ec6101f3e94b399f115fab45acc27c264267b3e Mon Sep 17 00:00:00 2001 From: Danila Klimenko Date: Fri, 17 Apr 2015 19:30:50 +0200 Subject: [PATCH] * Initial commit for the Chromatic binary search tree. Currently uses a readers-writers lock to synchronize access to the tree. * Basic tests for inserting, updating, retrieving and deleting elements (both single and multi threaded). --- base_cpp/include/embb/base/mutex.h | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h | 1559 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ containers_cpp/include/embb/containers/internal/object_pool-inl.h | 14 ++++++++++++++ containers_cpp/include/embb/containers/lock_free_chromatic_tree.h | 479 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ containers_cpp/include/embb/containers/object_pool.h | 5 +++++ containers_cpp/test/main.cc | 5 +++++ containers_cpp/test/tree_test-inl.h | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ containers_cpp/test/tree_test.h | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 2358 insertions(+) create mode 100644 containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h create mode 100644 containers_cpp/include/embb/containers/lock_free_chromatic_tree.h create mode 100644 containers_cpp/test/tree_test-inl.h create mode 100644 containers_cpp/test/tree_test.h diff --git a/base_cpp/include/embb/base/mutex.h b/base_cpp/include/embb/base/mutex.h index 0b8c7e3..fe51706 100644 --- a/base_cpp/include/embb/base/mutex.h +++ b/base_cpp/include/embb/base/mutex.h @@ -29,6 +29,7 @@ #include #include +#include namespace embb { namespace base { @@ -483,6 +484,71 @@ class UniqueLock { friend class embb::base::ConditionVariable; }; +class ReadWriteLock { + public: + ReadWriteLock() : read_lock_(), write_lock_(), + reader_(self()), writer_(self()) { + embb_counter_init(&active_readers_); + } + void ReadLock() { + LockGuard read_guard(read_lock_); + unsigned int me = embb_counter_increment(&active_readers_); + if (me == 0) { + write_lock_.Lock(); + } + } + void ReadUnlock() { + unsigned int me = embb_counter_decrement(&active_readers_); + if (me == 1) { + write_lock_.Unlock(); + } + } + void WriteLock() { + read_lock_.Lock(); + write_lock_.Lock(); + } + void WriteUnlock() { + write_lock_.Unlock(); + read_lock_.Unlock(); + } + ~ReadWriteLock() { + embb_counter_destroy(&active_readers_); + } + + class Reader { + public: + explicit Reader(ReadWriteLock& rwlock) : readwrite_lock_(rwlock) {} + void Lock() { readwrite_lock_.ReadLock(); } + void Unlock() { readwrite_lock_.ReadUnlock(); } + + private: + ReadWriteLock& readwrite_lock_; + }; + class Writer { + public: + explicit Writer(ReadWriteLock& rwlock) : readwrite_lock_(rwlock) {} + void Lock() { readwrite_lock_.WriteLock(); } + void Unlock() { readwrite_lock_.WriteUnlock(); } + + private: + ReadWriteLock& readwrite_lock_; + }; + Reader& GetReader() { return reader_; } + Writer& GetWriter() { return writer_; } + + private: + ReadWriteLock(const ReadWriteLock&); + ReadWriteLock& operator=(const ReadWriteLock&); + + ReadWriteLock& self() { return *this; } + + Mutex read_lock_; + Mutex write_lock_; + embb_counter_t active_readers_; + Reader reader_; + Writer writer_; +}; + } // namespace base } // namespace embb diff --git a/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h b/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h new file mode 100644 index 0000000..5d5cca2 --- /dev/null +++ b/containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h @@ -0,0 +1,1559 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_CONTAINERS_INTERNAL_LOCK_FREE_CHROMATIC_TREE_INL_H_ +#define EMBB_CONTAINERS_INTERNAL_LOCK_FREE_CHROMATIC_TREE_INL_H_ + +#include +#include + +namespace embb { +namespace containers { +namespace internal { + +template +ChromaticTreeNode:: +ChromaticTreeNode(const Key& key, const Value& value, const int& weight, + ChromaticTreeNode* const & left, + ChromaticTreeNode* const & right) + : key_(key), + value_(value), + weight_(weight), + left_(left), + right_(right) {} + +template +ChromaticTreeNode:: +ChromaticTreeNode(const Key& key, const Value& value) + : key_(key), + value_(value), + weight_(1), + left_(NULL), + right_(NULL) {} + +template +ChromaticTreeNode:: +ChromaticTreeNode(const ChromaticTreeNode& other) + : key_(other.key_), + value_(other.value_), + weight_(other.weight_), + left_(other.left_), + right_(other.right_) {} + +template +const Key& ChromaticTreeNode::GetKey() const { + return key_; +} + +template +const Value& ChromaticTreeNode::GetValue() const { + return value_; +} + +template +const int& ChromaticTreeNode::GetWeight() const { + return weight_; +} + +template +ChromaticTreeNode*& ChromaticTreeNode::GetLeft() { + return left_; +} + +template +ChromaticTreeNode*& ChromaticTreeNode::GetRight() { + return right_; +} + +} // namespace internal + + +template +ChromaticTree:: +ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value, + Compare compare) + : undefined_key_(undefined_key), + undefined_value_(undefined_value), + compare_(compare), + capacity_(capacity), + node_pool_(2 + 5 + 2 * capacity_) { + entry_ = node_pool_.Allocate(undefined_key_, undefined_value_); + NodePtr sentinel = node_pool_.Allocate(undefined_key_, undefined_value_); + entry_->GetLeft() = sentinel; +} + +template +ChromaticTree:: +~ChromaticTree() { + Destruct(entry_->GetLeft()); + node_pool_.Free(entry_); +} + +template +bool ChromaticTree:: +Get(const Key& key, Value& value) { + ReaderLockGuard guard(readwrite_lock_.GetReader()); + + NodePtr leaf; + Search(key, leaf); + + bool keys_are_equal = !(compare_(key, leaf->GetKey()) || + compare_(leaf->GetKey(), key)); + if (!IsSentinel(leaf) && keys_are_equal) { + value = leaf->GetValue(); + return true; + } else { + return false; + } +} + +template +bool ChromaticTree:: +TryInsert(const Key& key, const Value& value) { + Value old_value; + return TryInsert(key, value, old_value); +} + +template +bool ChromaticTree:: +TryInsert(const Key& key, const Value& value, Value& old_value) { + WriterLockGuard guard(readwrite_lock_.GetWriter()); + + NodePtr leaf, parent; + Search(key, leaf, parent); + + assert(HasChild(parent, leaf)); + + NodePtr new_parent; + bool added_violation = false; + + NodePtr new_leaf = node_pool_.Allocate(key, value); + if (new_leaf == NULL) { + return false; + } + + bool keys_are_equal = !(compare_(key, leaf->GetKey()) || + compare_(leaf->GetKey(), key)); + if (!IsSentinel(leaf) && keys_are_equal) { + old_value = leaf->GetValue(); + new_parent = new_leaf; + } else { + old_value = undefined_value_; + + NodePtr new_sibling = node_pool_.Allocate(*leaf); + if (new_sibling == NULL) { + node_pool_.Free(new_leaf); + return false; + } + + int new_weight = (HasFixedWeight(leaf)) ? 1 : (leaf->GetWeight() - 1); + if (IsSentinel(leaf) || compare_(key, leaf->GetKey())) { + new_parent = node_pool_.Allocate( + leaf->GetKey(), undefined_value_, new_weight, new_leaf, new_sibling); + } else { + new_parent = node_pool_.Allocate( + key, undefined_value_, new_weight, new_sibling, new_leaf); + } + + if (new_parent == NULL) { + node_pool_.Free(new_leaf); + node_pool_.Free(new_sibling); + return false; + } + + added_violation = (parent->GetWeight() == 0 && new_weight == 0); + } + + NodePtr& new_subtree_ptr = GetPointerToChild(parent, leaf); + new_subtree_ptr = new_parent; + + node_pool_.Free(leaf); + + if (added_violation) { + CleanUp(key); + } + + return true; +} + +template +bool ChromaticTree:: +TryDelete(const Key& key) { + Value old_value; + return TryDelete(key, old_value); +} + +template +bool ChromaticTree:: +TryDelete(const Key& key, Value& old_value) { + WriterLockGuard guard(readwrite_lock_.GetWriter()); + + NodePtr leaf, parent, grandparent; + Search(key, leaf, parent, grandparent); + + bool keys_are_equal = !(compare_(key, leaf->GetKey()) || + compare_(leaf->GetKey(), key)); + if (IsSentinel(leaf) || !keys_are_equal) { + old_value = undefined_value_; + return false; + } + + assert(HasChild(grandparent, parent)); + assert(HasChild(parent, leaf)); + + NodePtr sibling = ((parent->GetLeft() == leaf) ? + parent->GetRight() : parent->GetLeft()); + + int new_weight = (HasFixedWeight(parent)) ? + 1 : (parent->GetWeight() + sibling->GetWeight()); + bool added_violation = (new_weight > 1); + + NodePtr new_leaf = node_pool_.Allocate( + sibling->GetKey(), sibling->GetValue(), new_weight, + sibling->GetLeft(), sibling->GetRight()); + assert((new_leaf != NULL) && "No nodes available for replacement!"); + + NodePtr& new_subtree_ptr = GetPointerToChild(grandparent, parent); + new_subtree_ptr = new_leaf; + + old_value = leaf->GetValue(); + + node_pool_.Free(leaf); + node_pool_.Free(sibling); + node_pool_.Free(parent); + + if (added_violation) { + CleanUp(key); + } + + return true; +} + +template +size_t ChromaticTree:: +GetCapacity() { + return capacity_; +} + +template +const Value& ChromaticTree:: +GetUndefinedValue() { + return undefined_value_; +} + +template +bool ChromaticTree:: +IsEmpty() { + return IsLeaf(entry_->GetLeft()); +} + +template +void ChromaticTree:: +Search(const Key& key, NodePtr& leaf) const { + NodePtr parent; + Search(key, leaf, parent); +} + +template +void ChromaticTree:: +Search(const Key& key, NodePtr& leaf, NodePtr& parent) const { + NodePtr grandparent; + Search(key, leaf, parent, grandparent); +} + +template +void ChromaticTree:: +Search(const Key& key, NodePtr& leaf, NodePtr& parent, + NodePtr& grandparent) const { + grandparent = NULL; + parent = entry_; + leaf = entry_->GetLeft(); + + while (!IsLeaf(leaf)) { + grandparent = parent; + parent = leaf; + leaf = (IsSentinel(leaf) || compare_(key, leaf->GetKey())) ? + leaf->GetLeft() : leaf->GetRight(); + } +} + +template +bool ChromaticTree:: +IsLeaf(const NodePtr& node) const { + return node->GetLeft() == NULL; +} + +template +bool ChromaticTree:: +IsSentinel(const NodePtr& node) const { + return (node == entry_) || (node == entry_->GetLeft()); +} + +template +bool ChromaticTree:: +HasFixedWeight(const NodePtr& node) const { + return (IsSentinel(node)) || (node == entry_->GetLeft()->GetLeft()); +} + +template +bool ChromaticTree:: +HasChild(const NodePtr& parent, const NodePtr& child) const { + return (parent->GetLeft() == child || parent->GetRight() == child); +} + +template +typename ChromaticTree::NodePtr& +ChromaticTree:: +GetPointerToChild(const NodePtr& parent, const NodePtr& child) const { + assert(HasChild(parent, child)); + return (parent->GetLeft() == child) ? parent->GetLeft() : parent->GetRight(); +} + +template +void ChromaticTree:: +Destruct(const NodePtr& node) { + if (!IsLeaf(node)) { + Destruct(node->GetLeft()); + Destruct(node->GetRight()); + } + node_pool_.Free(node); +} + +template +bool ChromaticTree:: +CleanUp(const Key& key) { + while (true) { + NodePtr grandgrandparent = NULL; + NodePtr grandparent = NULL; + NodePtr parent = entry_; + NodePtr leaf = entry_->GetLeft(); + + while (!IsLeaf(leaf) && (leaf->GetWeight() <= 1) && + (leaf->GetWeight() != 0 || parent->GetWeight() != 0)) { + grandgrandparent = grandparent; + grandparent = parent; + parent = leaf; + leaf = (IsSentinel(leaf) || compare_(key, leaf->GetKey())) ? + leaf->GetLeft() : leaf->GetRight(); + } + + if (leaf->GetWeight() == 1) { + break; + } + + if (!Rebalance(grandgrandparent, grandparent, parent, leaf)) { + return false; + } + } + + return true; +} + +template +bool ChromaticTree:: +Rebalance(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, + const NodePtr& uxxx) { + //TODO: weakLLX(u); + if (!HasChild(u, ux)) return false; + + //TODO: weakLLX(ux); + NodePtr uxl = ux->GetLeft(); + NodePtr uxr = ux->GetRight(); + bool uxx_is_left = (uxx == uxl); + if (!HasChild(ux, uxx)) return false; + + //TODO: weakLLX(uxx); + NodePtr uxxl = uxx->GetLeft(); + NodePtr uxxr = uxx->GetRight(); + bool uxxx_is_left = (uxxx == uxxl); + if (!HasChild(uxx, uxxx)) return false; + + if (uxxx->GetWeight() > 1) { + if (uxxx_is_left) { + //TODO: weakLLX(uxxl); + return OverweightLeft(u, ux, uxx, uxl, uxr, uxxl, uxxr, uxx_is_left); + } else { + //TODO: weakLLX(uxxr); + return OverweightRight(u, ux, uxx, uxl, uxr, uxxl, uxxr, !uxx_is_left); + } + } else { + if (uxx_is_left) { + if (uxr->GetWeight() == 0) { + //TODO: weakLLX(uxr); + return BLK(u, ux, uxx, uxr); + } else if (uxxx_is_left) { + return RB1_L(u, ux, uxx); + } else { + //TODO: weakLLX(uxxr); + return RB2_L(u, ux, uxx, uxxr); + } + } else { + if (uxl->GetWeight() == 0) { + //TODO: weakLLX(uxl); + return BLK(u, ux, uxl, uxx); + } else if (!uxxx_is_left) { + return RB1_R(u, ux, uxx); + } else { + //TODO: weakLLX(uxxl); + return RB2_R(u, ux, uxx, uxxl); + } + } + } +} + +template +bool ChromaticTree:: +OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxxl, const NodePtr& uxxr, + const bool& uxx_is_left) { + // Let "Root" be the top of the overweight violation decision tree (see p.30) + // Root -> Middle + if (uxxr->GetWeight() == 0) { + // Root -> Middle -> Left + if (uxx->GetWeight() == 0) { + // Root -> Middle -> Left -> Left + if (uxx_is_left) { + // Root -> Middle -> Left -> Left -> Left + if (uxr->GetWeight() == 0) { + //TODO: weakLLX(uxr); + return BLK(u, ux, uxx, uxr); + + // Root -> Middle -> Left -> Left -> Right + } else { + assert(uxr->GetWeight() > 0); + //TODO: weakLLX(uxxr); + return RB2_L(u, ux, uxx, uxxr); + } + + // Root -> Middle -> Left -> Right + } else { + assert(!uxx_is_left); + // Root -> Middle -> Left -> Right -> Left + if (uxl->GetWeight() == 0) { + //TODO: weakLLX(uxl); + return BLK(u, ux, uxl, uxx); + + // Root -> Middle -> Left -> Right -> Right + } else { + assert(uxl->GetWeight() > 0); + return RB1_R(u, ux, uxx); + } + } + + // Root -> Middle -> Right + } else { + assert(uxx->GetWeight() > 0); + //TODO: weakLLX(uxxr); + // Note: we know that 'uxxr' is not a leaf because it has weight 0. + NodePtr uxxrl = uxxr->GetLeft(); + //TODO: weakLLX(uxxrl); + + // Root -> Middle -> Right -> Left + if (uxxrl->GetWeight() == 0) { + return RB2_R(ux, uxx, uxxr, uxxrl); + + // Root -> Middle -> Right -> Middle + } else if (uxxrl->GetWeight() == 1) { + NodePtr uxxrll = uxxrl->GetLeft(); + NodePtr uxxrlr = uxxrl->GetRight(); + if (uxxrlr == NULL) return false; + + // Root -> Middle -> Right -> Middle -> Left + if (uxxrlr->GetWeight() == 0) { + //TODO: weakLLX(uxxrlr); + return W4_L(ux, uxx, uxxl, uxxr, uxxrl, uxxrlr); + + // Root -> Middle -> Right -> Middle -> Right + } else { + assert(uxxrlr->GetWeight() > 0); + // Root -> Middle -> Right -> Middle -> Right -> Left + if (uxxrll->GetWeight() == 0) { + //TODO: weakLLX(uxxrll); + return W3_L(ux, uxx, uxxl, uxxr, uxxrl, uxxrll); + + // Root -> Middle -> Right -> Middle -> Right -> Right + } else { + assert(uxxrll->GetWeight() > 0); + return W2_L(ux, uxx, uxxl, uxxr, uxxrl); + } + } + + // Root -> Middle -> Right -> Right + } else { + assert(uxxrl->GetWeight() > 1); + return W1_L(ux, uxx, uxxl, uxxr, uxxrl); + } + } + + // Root -> Right + } else if (uxxr->GetWeight() == 1) { + //TODO: weakLLX(uxxr); + NodePtr uxxrl = uxxr->GetLeft(); + NodePtr uxxrr = uxxr->GetRight(); + if (uxxrl == NULL) return false; + + // Root -> Right -> Left + if (uxxrr->GetWeight() == 0) { + //TODO: weakLLX(uxxrr); + return W5_L(ux, uxx, uxxl, uxxr, uxxrr); + + // Root -> Right -> Right + } else { + assert(uxxrr->GetWeight() > 0); + // Root -> Right -> Right -> Left + if (uxxrl->GetWeight() == 0) { + //TODO: weakLLX(uxxrl); + return W6_L(ux, uxx, uxxl, uxxr, uxxrl); + + // Root -> Right -> Right -> Right + } else { + assert(uxxrl->GetWeight() > 0); + return PUSH_L(ux, uxx, uxxl, uxxr); + } + } + + // Root -> Left + } else { + assert(uxxr->GetWeight() > 1); + //TODO: weakLLX(uxxr); + return W7(ux, uxx, uxxl, uxxr); + } + + return true; +} + +template +bool ChromaticTree:: +OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxxl, const NodePtr& uxxr, + const bool& uxx_is_right) { + // Let "Root" be the top of the overweight violation decision tree (see p.30) + // Root -> Middle + if (uxxl->GetWeight() == 0) { + // Root -> Middle -> Left + if (uxx->GetWeight() == 0) { + // Root -> Middle -> Left -> Left + if (uxx_is_right) { + // Root -> Middle -> Left -> Left -> Left + if (uxl->GetWeight() == 0) { + //TODO: weakLLX(uxl); + return BLK(u, ux, uxl, uxx); + + // Root -> Middle -> Left -> Left -> Right + } else { + assert(uxl->GetWeight() > 0); + //TODO: weakLLX(uxxl); + return RB2_R(u, ux, uxx, uxxl); + } + + // Root -> Middle -> Left -> Right + } else { + assert(!uxx_is_right); + // Root -> Middle -> Left -> Right -> Left + if (uxr->GetWeight() == 0) { + //TODO: weakLLX(uxr); + return BLK(u, ux, uxx, uxr); + + // Root -> Middle -> Left -> Right -> Right + } else { + assert(uxr->GetWeight() > 0); + return RB1_L(u, ux, uxx); + } + } + + // Root -> Middle -> Right + } else { + assert(uxx->GetWeight() > 0); + //TODO: weakLLX(uxxl); + // Note: we know that 'uxxl' is not a leaf because it has weight 0. + NodePtr uxxlr = uxxl->GetRight(); + //TODO: weakLLX(uxxlr); + + // Root -> Middle -> Right -> Left + if (uxxlr->GetWeight() == 0) { + return RB2_L(ux, uxx, uxxl, uxxlr); + + // Root -> Middle -> Right -> Middle + } else if (uxxlr->GetWeight() == 1) { + NodePtr uxxlrl = uxxlr->GetLeft(); + NodePtr uxxlrr = uxxlr->GetRight(); + if (uxxlrl == NULL) return false; + + // Root -> Middle -> Right -> Middle -> Left + if (uxxlrl->GetWeight() == 0) { + //TODO: weakLLX(uxxlrl); + return W4_R(ux, uxx, uxxl, uxxr, uxxlr, uxxlrl); + + // Root -> Middle -> Right -> Middle -> Right + } else { + assert(uxxlrl->GetWeight() > 0); + // Root -> Middle -> Right -> Middle -> Right -> Left + if (uxxlrr->GetWeight() == 0) { + //TODO: weakLLX(uxxlrr); + return W3_R(ux, uxx, uxxl, uxxr, uxxlr, uxxlrr); + + // Root -> Middle -> Right -> Middle -> Right -> Right + } else { + assert(uxxlrr->GetWeight() > 0); + return W2_R(ux, uxx, uxxl, uxxr, uxxlr); + } + } + + // Root -> Middle -> Right -> Right + } else { + assert(uxxlr->GetWeight() > 1); + return W1_R(ux, uxx, uxxl, uxxr, uxxlr); + } + } + + // Root -> Right + } else if (uxxl->GetWeight() == 1) { + //TODO: weakLLX(uxxl); + NodePtr uxxll = uxxl->GetLeft(); + NodePtr uxxlr = uxxl->GetRight(); + if (uxxll == NULL) return false; + + // Root -> Right -> Left + if (uxxll->GetWeight() == 0) { + //TODO: weakLLX(uxxll); + return W5_R(ux, uxx, uxxl, uxxr, uxxll); + + // Root -> Right -> Right + } else { + assert(uxxll->GetWeight() > 0); + // Root -> Right -> Right -> Left + if (uxxlr->GetWeight() == 0) { + //TODO: weakLLX(uxxlr); + return W6_R(ux, uxx, uxxl, uxxr, uxxlr); + + // Root -> Right -> Right -> Right + } else { + assert(uxxlr->GetWeight() > 0); + return PUSH_R(ux, uxx, uxxl, uxxr); + } + } + + // Root -> Left + } else { + assert(uxxl->GetWeight() > 1); + //TODO: weakLLX(uxxl); + return W7(ux, uxx, uxxl, uxxr); + } + + return true; +} + +template +int ChromaticTree:: +GetHeight(const NodePtr& node) const { + int height = 0; + if (node != NULL) { + height = 1 + ::std::max(GetHeight(node->GetLeft()), + GetHeight(node->GetRight())); + } + return height; +} + + +template +bool ChromaticTree:: +BLK(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr) { + NodePtr nxl = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nx = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + HasFixedWeight(ux) ? 1 : ux->GetWeight() - 1, + nxl, nxr); + + if (nxl == NULL || + nxr == NULL || + nx == NULL) { + if (nxl) node_pool_.Free(nxl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + + return true; +} + +template +bool ChromaticTree:: +PUSH_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr) { + NodePtr nxl = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + 0, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nx = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + HasFixedWeight(ux) ? 1 : ux->GetWeight() + 1, + nxl, nxr); + + if (nxl == NULL || + nxr == NULL || + nx == NULL) { + if (nxl) node_pool_.Free(nxl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + + return true; +} + +template +bool ChromaticTree:: +PUSH_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr) { + NodePtr nxr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nxl = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + 0, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nx = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + HasFixedWeight(ux) ? 1 : ux->GetWeight() + 1, + nxl, nxr); + + if (nxr == NULL || + nxl == NULL || + nx == NULL) { + if (nxr) node_pool_.Free(nxr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + + return true; +} + +template +bool ChromaticTree:: +RB1_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl) { + NodePtr nxr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 0, + uxl->GetRight(), ux->GetRight()); + NodePtr nx = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + ux->GetWeight(), + uxl->GetLeft(), nxr); + + if (nxr == NULL || + nx == NULL) { + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + + return true; +} + +template +bool ChromaticTree:: +RB1_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxr) { + NodePtr nxl = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 0, + ux->GetLeft(), uxr->GetLeft()); + NodePtr nx = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + ux->GetWeight(), + nxl, uxr->GetRight()); + + if (nxl == NULL || + nx == NULL) { + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxr); + + return true; +} + +template +bool ChromaticTree:: +RB2_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxlr) { + NodePtr nxl = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + 0, + uxl->GetLeft(), uxlr->GetLeft()); + NodePtr nxr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 0, + uxlr->GetRight(), ux->GetRight()); + NodePtr nx = node_pool_.Allocate( + uxlr->GetKey(), uxlr->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxl == NULL || + nxr == NULL || + nx == NULL) { + if (nxl) node_pool_.Free(nxl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxlr); + + return true; +} + +template +bool ChromaticTree:: +RB2_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxr, + const NodePtr& uxrl) { + NodePtr nxr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + 0, + uxrl->GetRight(), uxr->GetRight()); + NodePtr nxl = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 0, + ux->GetLeft(), uxrl->GetLeft()); + NodePtr nx = node_pool_.Allocate( + uxrl->GetKey(), uxrl->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxr == NULL || + nxl == NULL || + nx == NULL) { + if (nxr) node_pool_.Free(nxr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxr); + node_pool_.Free(uxrl); + + return true; +} + +template +bool ChromaticTree:: +W1_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxrl) { + NodePtr nxll = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxlr = node_pool_.Allocate( + uxrl->GetKey(), uxrl->GetValue(), + uxrl->GetWeight() - 1, + uxrl->GetLeft(), uxrl->GetRight()); + NodePtr nxl = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxll, nxlr); + NodePtr nx = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + ux->GetWeight(), + nxl, uxr->GetRight()); + + if (nxll == NULL || + nxlr == NULL || + nxl == NULL || + nx == NULL) { + if (nxll) node_pool_.Free(nxll); + if (nxlr) node_pool_.Free(nxlr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxrl); + + return true; +} + +template +bool ChromaticTree:: +W1_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxlr) { + NodePtr nxrr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nxrl = node_pool_.Allocate( + uxlr->GetKey(), uxlr->GetValue(), + uxlr->GetWeight() - 1, + uxlr->GetLeft(), uxlr->GetRight()); + NodePtr nxr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxrl, nxrr); + NodePtr nx = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + ux->GetWeight(), + uxl->GetLeft(), nxr); + + if (nxrr == NULL || + nxrl == NULL || + nxr == NULL || + nx == NULL) { + if (nxrr) node_pool_.Free(nxrr); + if (nxrl) node_pool_.Free(nxrl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxlr); + + return true; +} + +template +bool ChromaticTree:: +W2_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxrl) { + NodePtr nxll = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxlr = node_pool_.Allocate( + uxrl->GetKey(), uxrl->GetValue(), + 0, + uxrl->GetLeft(), uxrl->GetRight()); + NodePtr nxl = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxll, nxlr); + NodePtr nx = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + ux->GetWeight(), + nxl, uxr->GetRight()); + + if (nxll == NULL || + nxlr == NULL || + nxl == NULL || + nx == NULL) { + if (nxll) node_pool_.Free(nxll); + if (nxlr) node_pool_.Free(nxlr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxrl); + + return true; +} + +template +bool ChromaticTree:: +W2_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxlr) { + NodePtr nxrr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nxrl = node_pool_.Allocate( + uxlr->GetKey(), uxlr->GetValue(), + 0, + uxlr->GetLeft(), uxlr->GetRight()); + NodePtr nxr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxrl, nxrr); + NodePtr nx = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + ux->GetWeight(), + uxl->GetLeft(), nxr); + + if (nxrr == NULL || + nxrl == NULL || + nxr == NULL || + nx == NULL) { + if (nxrr) node_pool_.Free(nxrr); + if (nxrl) node_pool_.Free(nxrl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxlr); + + return true; +} + +template +bool ChromaticTree:: +W3_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxrl, + const NodePtr& uxrll) { + NodePtr nxlll = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxll = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxlll, uxrll->GetLeft()); + NodePtr nxlr = node_pool_.Allocate( + uxrl->GetKey(), uxrl->GetValue(), + 1, + uxrll->GetRight(), uxrl->GetRight()); + NodePtr nxl = node_pool_.Allocate( + uxrll->GetKey(), uxrll->GetValue(), + 0, + nxll, nxlr); + NodePtr nx = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + ux->GetWeight(), + nxl, uxr->GetRight()); + + if (nxlll == NULL || + nxll == NULL || + nxlr == NULL || + nxl == NULL || + nx == NULL) { + if (nxlll) node_pool_.Free(nxlll); + if (nxll) node_pool_.Free(nxll); + if (nxlr) node_pool_.Free(nxlr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxrl); + node_pool_.Free(uxrll); + + return true; +} + +template +bool ChromaticTree:: +W3_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxlr, + const NodePtr& uxlrr) { + NodePtr nxrrr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nxrr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + uxlrr->GetRight(), nxrrr); + NodePtr nxrl = node_pool_.Allocate( + uxlr->GetKey(), uxlr->GetValue(), + 1, + uxlr->GetLeft(), uxlrr->GetLeft()); + NodePtr nxr = node_pool_.Allocate( + uxlrr->GetKey(), uxlrr->GetValue(), + 0, + nxrl, nxrr); + NodePtr nx = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + ux->GetWeight(), + uxl->GetLeft(), nxr); + + if (nxrrr == NULL || + nxrr == NULL || + nxrl == NULL || + nxr == NULL || + nx == NULL) { + if (nxrrr) node_pool_.Free(nxrrr); + if (nxrr) node_pool_.Free(nxrr); + if (nxrl) node_pool_.Free(nxrl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxlr); + node_pool_.Free(uxlrr); + + return true; +} + +template +bool ChromaticTree:: +W4_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxrl, + const NodePtr& uxrlr) { + NodePtr nxll = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxrl = node_pool_.Allocate( + uxrlr->GetKey(), uxrlr->GetValue(), + 1, + uxrlr->GetLeft(), uxrlr->GetRight()); + NodePtr nxl = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxll, uxrl->GetLeft()); + NodePtr nxr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + 0, + nxrl, uxr->GetRight()); + NodePtr nx = node_pool_.Allocate( + uxrl->GetKey(), uxrl->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxll == NULL || + nxrl == NULL || + nxl == NULL || + nxr == NULL || + nx == NULL) { + if (nxll) node_pool_.Free(nxll); + if (nxrl) node_pool_.Free(nxrl); + if (nxl) node_pool_.Free(nxl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxrl); + node_pool_.Free(uxrlr); + + return true; +} + +template +bool ChromaticTree:: +W4_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxlr, + const NodePtr& uxlrl) { + NodePtr nxrr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nxlr = node_pool_.Allocate( + uxlrl->GetKey(), uxlrl->GetValue(), + 1, + uxlrl->GetLeft(), uxlrl->GetRight()); + NodePtr nxr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + uxlr->GetRight(), nxrr); + NodePtr nxl = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + 0, + uxl->GetLeft(), nxlr); + NodePtr nx = node_pool_.Allocate( + uxlr->GetKey(), uxlr->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxrr == NULL || + nxlr == NULL || + nxr == NULL || + nxl == NULL || + nx == NULL) { + if (nxrr) node_pool_.Free(nxrr); + if (nxlr) node_pool_.Free(nxlr); + if (nxr) node_pool_.Free(nxr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxlr); + node_pool_.Free(uxlrl); + + return true; +} + +template +bool ChromaticTree:: +W5_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxrr) { + NodePtr nxll = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxl = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxll, uxr->GetLeft()); + NodePtr nxr = node_pool_.Allocate( + uxrr->GetKey(), uxrr->GetValue(), + 1, + uxrr->GetLeft(), uxrr->GetRight()); + NodePtr nx = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxll == NULL || + nxl == NULL || + nxr == NULL || + nx == NULL) { + if (nxll) node_pool_.Free(nxll); + if (nxl) node_pool_.Free(nxl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxrr); + + return true; +} + +template +bool ChromaticTree:: +W5_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxll) { + NodePtr nxrr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nxr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + uxl->GetRight(), nxrr); + NodePtr nxl = node_pool_.Allocate( + uxll->GetKey(), uxll->GetValue(), + 1, + uxll->GetLeft(), uxll->GetRight()); + NodePtr nx = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxrr == NULL || + nxr == NULL || + nxl == NULL || + nx == NULL) { + if (nxrr) node_pool_.Free(nxrr); + if (nxr) node_pool_.Free(nxr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxll); + + return true; +} + +template +bool ChromaticTree:: +W6_L(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxrl) { + NodePtr nxll = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxl = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + nxll, uxrl->GetLeft()); + NodePtr nxr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + 1, + uxrl->GetRight(), uxr->GetRight()); + NodePtr nx = node_pool_.Allocate( + uxrl->GetKey(), uxrl->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxll == NULL || + nxl == NULL || + nxr == NULL || + nx == NULL) { + if (nxll) node_pool_.Free(nxll); + if (nxl) node_pool_.Free(nxl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxrl); + + return true; +} + +template +bool ChromaticTree:: +W6_R(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr, + const NodePtr& uxlr) { + NodePtr nxrr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nxr = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + 1, + uxlr->GetRight(), nxrr); + NodePtr nxl = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + 1, + uxl->GetLeft(), uxlr->GetLeft()); + NodePtr nx = node_pool_.Allocate( + uxlr->GetKey(), uxlr->GetValue(), + ux->GetWeight(), + nxl, nxr); + + if (nxrr == NULL || + nxr == NULL || + nxl == NULL || + nx == NULL) { + if (nxrr) node_pool_.Free(nxrr); + if (nxr) node_pool_.Free(nxr); + if (nxl) node_pool_.Free(nxl); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + node_pool_.Free(uxlr); + + return true; +} + +template +bool ChromaticTree:: +W7(const NodePtr& u, + const NodePtr& ux, + const NodePtr& uxl, + const NodePtr& uxr) { + NodePtr nxl = node_pool_.Allocate( + uxl->GetKey(), uxl->GetValue(), + uxl->GetWeight() - 1, + uxl->GetLeft(), uxl->GetRight()); + NodePtr nxr = node_pool_.Allocate( + uxr->GetKey(), uxr->GetValue(), + uxr->GetWeight() - 1, + uxr->GetLeft(), uxr->GetRight()); + NodePtr nx = node_pool_.Allocate( + ux->GetKey(), ux->GetValue(), + HasFixedWeight(ux) ? 1 : ux->GetWeight() + 1, + nxl, nxr); + + if (nxl == NULL || + nxr == NULL || + nx == NULL) { + if (nxl) node_pool_.Free(nxl); + if (nxr) node_pool_.Free(nxr); + if (nx) node_pool_.Free(nx); + return false; + } + + NodePtr& new_subtree_ptr = GetPointerToChild(u, ux); + new_subtree_ptr = nx; + + node_pool_.Free(ux); + node_pool_.Free(uxl); + node_pool_.Free(uxr); + + return true; +} + + +} // namespace containers +} // namespace embb + +#endif // EMBB_CONTAINERS_INTERNAL_LOCK_FREE_CHROMATIC_TREE_INL_H_ diff --git a/containers_cpp/include/embb/containers/internal/object_pool-inl.h b/containers_cpp/include/embb/containers/internal/object_pool-inl.h index 61711d5..cef483c 100644 --- a/containers_cpp/include/embb/containers/internal/object_pool-inl.h +++ b/containers_cpp/include/embb/containers/internal/object_pool-inl.h @@ -187,6 +187,20 @@ Type* ObjectPool::Allocate( } template +template +Type* ObjectPool::Allocate( + Param1 const& param1, Param2 const& param2, + Param3 const& param3, Param4 const& param4, + Param5 const& param5) { + Type* rawObject = AllocateRaw(); + if (rawObject != NULL) + new (rawObject)Type(param1, param2, param3, param4, param5); + + return rawObject; +} + +template ObjectPool::~ObjectPool() { // Deallocate the objects objectAllocator.deallocate(objects, capacity); diff --git a/containers_cpp/include/embb/containers/lock_free_chromatic_tree.h b/containers_cpp/include/embb/containers/lock_free_chromatic_tree.h new file mode 100644 index 0000000..9b191a7 --- /dev/null +++ b/containers_cpp/include/embb/containers/lock_free_chromatic_tree.h @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_H_ +#define EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_H_ + +#include +#include + +#include + +namespace embb { +namespace containers { +namespace internal { + +/** + * Tree node + * + * Stores the key-value pair, as well as the weight value (used for rebalancing) + * and two pointers to child nodes (left and right). + * + * \tparam Key Key type + * \tparam Value Value type + */ +template +class ChromaticTreeNode { + public: + /** + * Creates a node with given parameters. + * + * \param[IN] key Key of the new node + * \param[IN] value Value of the new node + * \param[IN] weight Weight of the new node + * \param[IN] left Pointer to the left child node + * \param[IN] right Pointer to the right child node + */ + ChromaticTreeNode(const Key& key, const Value& value, const int& weight, + ChromaticTreeNode* const & left, + ChromaticTreeNode* const & right); + + /** + * Creates a node given only a key-value pair. Node will have no child nodes + * and a default weight (1). + * + * \param[IN] key Key of the new node + * \param[IN] value Value of the new node + */ + ChromaticTreeNode(const Key& key, const Value& value); + + /** + * Creates a copy of a given node. + * + * \param[IN] other Node to be copied + */ + ChromaticTreeNode(const ChromaticTreeNode& other); + + + /** + * Accessor for the stored key. + * + * \return Stored key + */ + const Key& GetKey() const; + + /** + * Accessor for the stored value. + * + * \return Stored value + */ + const Value& GetValue() const; + + /** + * Accessor for the weight of the node. + * + * \return Weight of the node + */ + const int& GetWeight() const; + + /** + * Accessor for the left child pointer. + * + * \return Reference to the left child pointer + */ + ChromaticTreeNode*& GetLeft(); + + /** + * Accessor for the right child pointer. + * + * \return Reference to the right child pointer + */ + ChromaticTreeNode*& GetRight(); + + private: + const Key key_; /**< Stored key */ + const Value value_; /**< Stored value */ + const int weight_; /**< Weight of the node */ + ChromaticTreeNode* left_; /**< Pointer to left child node */ + ChromaticTreeNode* right_; /**< Pointer to right child node */ +}; + +} // namespace internal + + +/** + * Chromatic balanced binary search tree + * + * Implements a balanced BST with support for \c Get, \c Insert and \c Delete + * operations. + * + * \tparam Key Key type + * \tparam Value Value type + * \tparam Compare Custom comparator type for the keys. An object of the + * type \c Compare must must be a functor taking two + * arguments \c rhs and \c lhs of type \c Key and + * returning \c true if and only if (rhs < lhs) holds + * \tparam NodePool The object pool type used for allocation/deallocation + * of tree nodes. + */ +template, + typename NodePool = ObjectPool, + LockFreeTreeValuePool > + > +class ChromaticTree { + public: + /** + * Creates a new tree with given capacity. + * + * \memory Allocates (2 * capacity + 7) tree nodes each of size + * sizeof(internal::ChromaticTreeNode). + * + * \notthreadsafe + * + * \param[IN] capacity Required capacity of the tree + * \param[IN] undefined_key Object of type \c Key to be used as a dummy key. + * Defaults to Key() + * \param[IN] undefined_value Object of type \c Value to be used as a dummy + * value. Defaults to Value() + * \param[IN] compare Custom comparator object for managed keys. + * Defaults to Compare() + * + * \note If any of \c undefined_key, \c undefined_value or \c compare is not + * provided, that will require the corresponding type (\c Key, \c Value + * or \c Compare) to support value-initialization. + */ + explicit ChromaticTree(size_t capacity, Key undefined_key = Key(), + Value undefined_value = Value(), Compare compare = Compare()); + + /** + * Destroys the tree. + * + * \notthreadsafe + */ + ~ChromaticTree(); + + + /** + * Tries to find a value for the given key. + * + * \param[IN] key Key to search for + * \param[IN,OUT] value Reference to the found value. Unchanged if the given + * key is not stored in the tree + * + * \return \c true if the given key was found in the tree, \c false otherwise + */ + bool Get(const Key& key, Value& value); + + /** + * Tries to insert a new key-value pair into the tree. If a value for the + * given key is already stored in the tree, tries to replace the stored value + * with the new one. + * + * \param[IN] key New key to be inserted + * \param[IN] value New value to be inserted + * + * \return \c true if the given key-value pair was successfully inserted into + * the tree, \c false if tree has reached its capacity + */ + bool TryInsert(const Key& key, const Value& value); + + /** + * Tries to insert a new key-value pair into the tree. If a value for the + * given key is already stored in the tree, tries to replace the stored value + * with the new one. Also returns the original value stored in the tree for + * the given \c key, or the \c undefined_value if the key was not present in + * the tree. + * + * \param[IN] key New key to be inserted + * \param[IN] value New value to be inserted + * \param[IN,OUT] old_value Reference to the value previously stored in the + * tree for the given key + * + * \return \c true if the given key-value pair was successfully inserted into + * the tree, \c false if tree has reached its capacity + */ + bool TryInsert(const Key& key, const Value& value, Value& old_value); + + /** + * Tries to remove a given key-value pair from the tree. + * + * \param[IN] key Key to be removed + * + * \return \c true if the given key-value pair was successfully deleted from + * the tree, \c false if the given key was not stored in the tree + */ + bool TryDelete(const Key& key); + + /** + * Tries to remove a given key-value pair from the tree, and returns the value + * that was stored in the tree for the given key (or \c undefined_value if + * the key was not present in the tree). + * + * \param[IN] key Key to be removed + * \param[IN,OUT] old_value Reference to the value previously stored in the + * tree for the given key + * + * \return \c true if the given key-value pair was successfully deleted from + * the tree, \c false if the given key was not stored in the tree + */ + bool TryDelete(const Key& key, Value& old_value); + + + /** + * Accessor for the capacity of the tree. + * + * \return Number of key-value pairs the tree can store + */ + size_t GetCapacity(); + + /** + * Accessor for the dummy value used by the tree + * + * \return Object of type \c Value that is used by the tree as a dummy value + */ + const Value& GetUndefinedValue(); + + /** + * Checks whether the tree is currently empty. + * + * \return \c true if the tree stores no key-value pairs, \c false otherwise + */ + bool IsEmpty(); + + private: + /** + * Typedef for a node of the tree. + */ + typedef internal::ChromaticTreeNode Node; + /** + * Typedef for a pointer to a node of the tree. + */ + typedef internal::ChromaticTreeNode* NodePtr; + + + /** + * Follows a path from the root of the tree to some leaf searching for the + * given key (the leaf found by this method may or may not contain the given + * key). Returns the reached leaf. + * + * \param[IN] key Key to be searched for + * \param[IN,OUT] leaf Reference to the reached leaf + */ + void Search(const Key& key, NodePtr& leaf) const; + + /** + * Follows a path from the root of the tree to some leaf searching for the + * given key (the leaf found by this method may or may not contain the given + * key). Returns the reached leaf together with its ancestors. + * + * \param[IN] key Key to be searched for + * \param[IN,OUT] leaf Reference to the reached leaf + * \param[IN,OUT] parent Reference to the parent of the reached leaf + */ + void Search(const Key& key, NodePtr& leaf, NodePtr& parent) const; + + /** + * Follows a path from the root of the tree to some leaf searching for the + * given key (the leaf found by this method may or may not contain the given + * key). Returns the reached leaf together with its ancestors. + * + * \param[IN] key Key to be searched for + * \param[IN,OUT] leaf Reference to the reached leaf + * \param[IN,OUT] parent Reference to the parent of the reached leaf + * \param[IN,OUT] grandparent Reference to the grandparent of the reached leaf + */ + void Search(const Key& key, NodePtr& leaf, NodePtr& parent, + NodePtr& grandparent) const; + + /** + * Checks whether the given node is a leaf. + * + * \param[IN] node Node to be checked + * + * \return \c true if the given node is a leaf, \c false otherwise + */ + bool IsLeaf(const NodePtr& node) const; + + /** + * Checks whether the given node is a sentinel node. + * + * \param[IN] node Node to be checked + * + * \return \c true if the given node is a sentinel node, \c false otherwise + */ + bool IsSentinel(const NodePtr& node) const; + + /** + * Checks whether the given node has to maintain the constant weight of \c 1. + * + * \param[IN] node Node to be checked + * + * \return \c true if the given node has constant weight, \c false otherwise + */ + bool HasFixedWeight(const NodePtr& node) const; + + /** + * Checks whether the given node has a specified child node. + * + * \param[IN] parent Parent node + * \param[IN] child Node that is supposed to be a child of \c parent + * + * \return \c true if \c child is a child node of \c parent, \c false + * otherwise + */ + bool HasChild(const NodePtr& parent, const NodePtr& child) const; + + /** + * Accessor for the child pointer of a given parent to the specified child. + * + * \pre The \c child has to be an actual child of the \c parent. + * + * \param[IN] parent Parent node + * \param[IN] child Child node of the \c parent + * + * \return Reference to a member pointer of the \c parent that points to + * the \c child + */ + NodePtr& GetPointerToChild(const NodePtr& parent, const NodePtr& child) const; + + /** + * Destroys all the nodes of a subtree rooted at the given node, including the + * node itself. + * + * \notthreadsafe + * + * \param node Root of the subtree to be destroyed + */ + void Destruct(const NodePtr& node); + + /** + * Follows the path from the root to some leaf (directed by the given key) and + * checks for any tree balancing violations. If a violation is found, tries + * to fix it by using a set of rebalancing rotations. + * + * \param key Key to be searched for + * + * \return \c true if the tree was successfully rebalanced, \c false otherwise + */ + bool CleanUp(const Key& key); + + /** + * Next block of methods is used internally to keep the balance of the tree. + */ + bool Rebalance(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, + const NodePtr& uxxx); + bool OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxxl, const NodePtr& uxxr, + const bool& uxx_is_left); + bool OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxxl, const NodePtr& uxxr, + const bool& uxx_is_right); + bool BLK(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr); + bool PUSH_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr); + bool PUSH_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr); + bool RB1_L(const NodePtr& u, const NodePtr& ux, const NodePtr& uxl); + bool RB1_R(const NodePtr& u, const NodePtr& ux, const NodePtr& uxr); + bool RB2_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxlr); + bool RB2_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxr, const NodePtr& uxrl); + bool W1_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxrl); + bool W1_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxlr); + bool W2_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxrl); + bool W2_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxlr); + bool W3_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxrl, const NodePtr& uxrll); + bool W3_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxlr, const NodePtr& uxlrr); + bool W4_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxrl, const NodePtr& uxrlr); + bool W4_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxlr, const NodePtr& uxlrl); + bool W5_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxrr); + bool W5_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxll); + bool W6_L(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxrl); + bool W6_R(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr, + const NodePtr& uxlr); + bool W7(const NodePtr& u, const NodePtr& ux, + const NodePtr& uxl, const NodePtr& uxr); + + /** + * Computes the hight of the subtree rooted at the given node. + * + * \param[IN] node Root of the subtree for which the height is requested + * + * \return The height of a subtree rooted at node \c node. (The height of a + * leaf node is defined to be zero). + */ + int GetHeight(const NodePtr& node) const; + + const Key undefined_key_; /**< A dummy key used by the tree */ + const Value undefined_value_; /**< A dummy value used by the tree */ + const Compare compare_; /**< Comparator object for the keys */ + size_t capacity_; /**< User-requested capacity of the tree */ + NodePool node_pool_; /**< Comparator object for the keys */ + NodePtr entry_; /**< Pointer to the sentinel node used as + * the entry point into the tree */ + + typedef embb::base::ReadWriteLock::Reader ReadWriteLockReader; + typedef embb::base::ReadWriteLock::Writer ReadWriteLockWriter; + typedef embb::base::LockGuard ReaderLockGuard; + typedef embb::base::LockGuard WriterLockGuard; + embb::base::ReadWriteLock readwrite_lock_; +}; + +} // namespace containers +} // namespace embb + +#include + +#endif // EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_H_ diff --git a/containers_cpp/include/embb/containers/object_pool.h b/containers_cpp/include/embb/containers/object_pool.h index 0a94708..c4f6114 100644 --- a/containers_cpp/include/embb/containers/object_pool.h +++ b/containers_cpp/include/embb/containers/object_pool.h @@ -180,6 +180,11 @@ class ObjectPool { Type* Allocate(Param1 const& param1, Param2 const& param2, Param3 const& param3, Param4 const& param4); + template + Type* Allocate(Param1 const& param1, Param2 const& param2, + Param3 const& param3, Param4 const& param4, Param5 const& param5); + #endif }; } // namespace containers diff --git a/containers_cpp/test/main.cc b/containers_cpp/test/main.cc index 0e26fee..605fa75 100644 --- a/containers_cpp/test/main.cc +++ b/containers_cpp/test/main.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,7 @@ #include "./stack_test.h" #include "./hazard_pointer_test.h" #include "./object_pool_test.h" +#include "./tree_test.h" #define COMMA , @@ -50,11 +52,13 @@ using embb::containers::LockFreeMPMCQueue; using embb::containers::LockFreeStack; using embb::containers::LockFreeTreeValuePool; using embb::containers::WaitFreeArrayValuePool; +using embb::containers::ChromaticTree; using embb::containers::test::PoolTest; using embb::containers::test::HazardPointerTest; using embb::containers::test::QueueTest; using embb::containers::test::StackTest; using embb::containers::test::ObjectPoolTest; +using embb::containers::test::TreeTest; PT_MAIN("Data Structures C++") { unsigned int max_threads = static_cast( @@ -70,6 +74,7 @@ PT_MAIN("Data Structures C++") { PT_RUN(StackTest< LockFreeStack >); PT_RUN(ObjectPoolTest< LockFreeTreeValuePool >); PT_RUN(ObjectPoolTest< WaitFreeArrayValuePool >); + PT_RUN(TreeTest< ChromaticTree >); PT_EXPECT(embb_get_bytes_allocated() == 0); } diff --git a/containers_cpp/test/tree_test-inl.h b/containers_cpp/test/tree_test-inl.h new file mode 100644 index 0000000..42e1252 --- /dev/null +++ b/containers_cpp/test/tree_test-inl.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CONTAINERS_CPP_TEST_TREE_TEST_INL_H_ +#define CONTAINERS_CPP_TEST_TREE_TEST_INL_H_ + +#include +#include +#include + +#include "tree_test.h" + +namespace embb { +namespace containers { +namespace test { + +template +TreeTest::TreeTest() + : tree_(NULL) { + // Repeat twice to ensure that the tree remains operational after all the + // elements were removed from it + CreateUnit("TreeTestSingleThreadInsertDelete"). + Pre(&TreeTest::TreeTestSingleThreadInsertDelete_Pre, this). + Add(&TreeTest::TreeTestSingleThreadInsertDelete_ThreadMethod, this, 1, 2). + Post(&TreeTest::TreeTestSingleThreadInsertDelete_Post, this); + CreateUnit("TreeTestMultiThreadInsertDelete"). + Pre(&TreeTest::TreeTestSingleThreadInsertDelete_Pre, this). + Add(&TreeTest::TreeTestMultiThreadInsertDelete_ThreadMethod, this, + NUM_TEST_THREADS, 2). + Post(&TreeTest::TreeTestSingleThreadInsertDelete_Post, this); +} + +template +TreeTest::Worker:: +Worker(Tree& tree, size_t thread_id, int num_elements) + : tree_(tree), thread_id_(thread_id), num_elements_(num_elements) {} + +template +void TreeTest::Worker:: +Run() { + ElementVector elements; + for (int i = 0; i < num_elements_; ++i) { + Key key = i * 133 * 100 + thread_id_; + Value value = i * 133 * 100 + thread_id_; + elements.push_back(std::make_pair(key, value)); + } + + // Insert elements into the tree + ::std::random_shuffle(elements.begin(), elements.end()); + for (ElementIterator it = elements.begin(); it != elements.end(); ++it) { + bool success = tree_.TryInsert(it->first, it->second); + PT_ASSERT_MSG(success, "Failed to insert element into the tree."); + } + + // Verify that all inserted elements are available in the tree + ::std::random_shuffle(elements.begin(), elements.end()); + for (ElementIterator it = elements.begin(); it != elements.end(); ++it) { + Value value; + bool success = tree_.Get(it->first, value); + PT_ASSERT_MSG(success, "Failed to get an element from the tree."); + PT_ASSERT_MSG(it->second == value, "Wrong value retrieved from the tree."); + } + + // Replace some of the elements that were inserted earlier + ::std::random_shuffle(elements.begin(), elements.end()); + ElementIterator elements_middle = elements.begin() + num_elements_ / 2; + for (ElementIterator it = elements.begin(); it != elements_middle; ++it) { + it->second *= 13; + bool success = tree_.TryInsert(it->first, it->second); + PT_ASSERT_MSG(success, "Failed to insert element into the tree."); + } + + // Verify again that all elements are in the tree and have correct values + ::std::random_shuffle(elements.begin(), elements.end()); + for (ElementIterator it = elements.begin(); it != elements.end(); ++it) { + Value value; + bool success = tree_.Get(it->first, value); + PT_ASSERT_MSG(success, "Failed to get an element from the tree."); + PT_ASSERT_MSG(it->second == value, "Wrong value retrieved from the tree."); + } + + // Delete elements from the tree + ::std::random_shuffle(elements.begin(), elements.end()); + for (ElementIterator it = elements.begin(); it != elements.end(); ++it) { + Value value; + bool success = tree_.TryDelete(it->first, value); + PT_ASSERT_MSG(success, "Failed to delete element from the tree."); + PT_ASSERT_MSG(it->second == value, "Wrong value deleted from the tree."); + } +} + +template +void TreeTest:: +TreeTestSingleThreadInsertDelete_Pre() { + tree_ = new Tree(TREE_CAPACITY); +} + +template +void TreeTest:: +TreeTestSingleThreadInsertDelete_ThreadMethod() { + size_t thread_id = partest::TestSuite::GetCurrentThreadID(); + + Worker worker(*tree_, thread_id, TREE_CAPACITY); + + worker.Run(); +} + +template +void TreeTest:: +TreeTestMultiThreadInsertDelete_ThreadMethod() { + size_t thread_id = partest::TestSuite::GetCurrentThreadID(); + + int num_elements = TREE_CAPACITY / (NUM_TEST_THREADS + 1); + if (thread_id == 0) { + num_elements *= 2; + } + Worker worker(*tree_, thread_id, num_elements); + + worker.Run(); +} + +template +void TreeTest:: +TreeTestSingleThreadInsertDelete_Post() { + PT_ASSERT_MSG((tree_->IsEmpty()), "The tree must be empty at this point."); + delete tree_; +} + +} // namespace test +} // namespace containers +} // namespace embb + +#endif // CONTAINERS_CPP_TEST_TREE_TEST_INL_H_ diff --git a/containers_cpp/test/tree_test.h b/containers_cpp/test/tree_test.h new file mode 100644 index 0000000..1c42805 --- /dev/null +++ b/containers_cpp/test/tree_test.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2014-2015, Siemens AG. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CONTAINERS_CPP_TEST_TREE_TEST_H_ +#define CONTAINERS_CPP_TEST_TREE_TEST_H_ + +namespace embb { +namespace containers { +namespace test { + +template +class TreeTest : public partest::TestCase { + public: + TreeTest(); + + private: + class Worker { + public: + Worker(Tree& tree, size_t thread_id, int num_elements); + void Run(); + + private: + Tree& tree_; + size_t thread_id_; + int num_elements_; + }; + + typedef int Key; + typedef int Value; + typedef ::std::pair Element; + typedef ::std::vector ElementVector; + typedef ElementVector::iterator ElementIterator; + + static const int TREE_CAPACITY = 2000; + static const int NUM_TEST_THREADS = 3; + + void TreeTestSingleThreadInsertDelete_Pre(); + void TreeTestSingleThreadInsertDelete_ThreadMethod(); + void TreeTestMultiThreadInsertDelete_ThreadMethod(); + void TreeTestSingleThreadInsertDelete_Post(); + + Tree *tree_; +}; + +} // namespace test +} // namespace containers +} // namespace embb + +#include "./tree_test-inl.h" + +#endif // CONTAINERS_CPP_TEST_TREE_TEST_H_ -- libgit2 0.26.0