Commit 6ec6101f by Danila Klimenko

* Initial commit for the Chromatic binary search tree. Currently uses a…

* 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).
parent 5abeb065
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <embb/base/internal/platform.h> #include <embb/base/internal/platform.h>
#include <embb/base/exceptions.h> #include <embb/base/exceptions.h>
#include <embb/base/c/counter.h>
namespace embb { namespace embb {
namespace base { namespace base {
...@@ -483,6 +484,71 @@ class UniqueLock { ...@@ -483,6 +484,71 @@ class UniqueLock {
friend class embb::base::ConditionVariable; 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<Mutex> 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 base
} // namespace embb } // namespace embb
......
/*
* 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 <assert.h>
#include <algorithm>
namespace embb {
namespace containers {
namespace internal {
template<typename Key, typename Value>
ChromaticTreeNode<Key, Value>::
ChromaticTreeNode(const Key& key, const Value& value, const int& weight,
ChromaticTreeNode<Key, Value>* const & left,
ChromaticTreeNode<Key, Value>* const & right)
: key_(key),
value_(value),
weight_(weight),
left_(left),
right_(right) {}
template<typename Key, typename Value>
ChromaticTreeNode<Key, Value>::
ChromaticTreeNode(const Key& key, const Value& value)
: key_(key),
value_(value),
weight_(1),
left_(NULL),
right_(NULL) {}
template<typename Key, typename Value>
ChromaticTreeNode<Key, Value>::
ChromaticTreeNode(const ChromaticTreeNode& other)
: key_(other.key_),
value_(other.value_),
weight_(other.weight_),
left_(other.left_),
right_(other.right_) {}
template<typename Key, typename Value>
const Key& ChromaticTreeNode<Key, Value>::GetKey() const {
return key_;
}
template<typename Key, typename Value>
const Value& ChromaticTreeNode<Key, Value>::GetValue() const {
return value_;
}
template<typename Key, typename Value>
const int& ChromaticTreeNode<Key, Value>::GetWeight() const {
return weight_;
}
template<typename Key, typename Value>
ChromaticTreeNode<Key, Value>*& ChromaticTreeNode<Key, Value>::GetLeft() {
return left_;
}
template<typename Key, typename Value>
ChromaticTreeNode<Key, Value>*& ChromaticTreeNode<Key, Value>::GetRight() {
return right_;
}
} // namespace internal
template<typename Key, typename Value, typename Compare, typename NodePool>
ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
ChromaticTree<Key, Value, Compare, NodePool>::
~ChromaticTree() {
Destruct(entry_->GetLeft());
node_pool_.Free(entry_);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
TryInsert(const Key& key, const Value& value) {
Value old_value;
return TryInsert(key, value, old_value);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
TryDelete(const Key& key) {
Value old_value;
return TryDelete(key, old_value);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
size_t ChromaticTree<Key, Value, Compare, NodePool>::
GetCapacity() {
return capacity_;
}
template<typename Key, typename Value, typename Compare, typename NodePool>
const Value& ChromaticTree<Key, Value, Compare, NodePool>::
GetUndefinedValue() {
return undefined_value_;
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
IsEmpty() {
return IsLeaf(entry_->GetLeft());
}
template<typename Key, typename Value, typename Compare, typename NodePool>
void ChromaticTree<Key, Value, Compare, NodePool>::
Search(const Key& key, NodePtr& leaf) const {
NodePtr parent;
Search(key, leaf, parent);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
void ChromaticTree<Key, Value, Compare, NodePool>::
Search(const Key& key, NodePtr& leaf, NodePtr& parent) const {
NodePtr grandparent;
Search(key, leaf, parent, grandparent);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
void ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
IsLeaf(const NodePtr& node) const {
return node->GetLeft() == NULL;
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
IsSentinel(const NodePtr& node) const {
return (node == entry_) || (node == entry_->GetLeft());
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
HasFixedWeight(const NodePtr& node) const {
return (IsSentinel(node)) || (node == entry_->GetLeft()->GetLeft());
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
HasChild(const NodePtr& parent, const NodePtr& child) const {
return (parent->GetLeft() == child || parent->GetRight() == child);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
typename ChromaticTree<Key, Value, Compare, NodePool>::NodePtr&
ChromaticTree<Key, Value, Compare, NodePool>::
GetPointerToChild(const NodePtr& parent, const NodePtr& child) const {
assert(HasChild(parent, child));
return (parent->GetLeft() == child) ? parent->GetLeft() : parent->GetRight();
}
template<typename Key, typename Value, typename Compare, typename NodePool>
void ChromaticTree<Key, Value, Compare, NodePool>::
Destruct(const NodePtr& node) {
if (!IsLeaf(node)) {
Destruct(node->GetLeft());
Destruct(node->GetRight());
}
node_pool_.Free(node);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
int ChromaticTree<Key, Value, Compare, NodePool>::
GetHeight(const NodePtr& node) const {
int height = 0;
if (node != NULL) {
height = 1 + ::std::max(GetHeight(node->GetLeft()),
GetHeight(node->GetRight()));
}
return height;
}
template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>::
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_
...@@ -187,6 +187,20 @@ Type* ObjectPool<Type, ValuePool, ObjectAllocator>::Allocate( ...@@ -187,6 +187,20 @@ Type* ObjectPool<Type, ValuePool, ObjectAllocator>::Allocate(
} }
template<class Type, typename ValuePool, class ObjectAllocator> template<class Type, typename ValuePool, class ObjectAllocator>
template<typename Param1, typename Param2, typename Param3, typename Param4,
typename Param5>
Type* ObjectPool<Type, ValuePool, ObjectAllocator>::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<class Type, typename ValuePool, class ObjectAllocator>
ObjectPool<Type, ValuePool, ObjectAllocator>::~ObjectPool() { ObjectPool<Type, ValuePool, ObjectAllocator>::~ObjectPool() {
// Deallocate the objects // Deallocate the objects
objectAllocator.deallocate(objects, capacity); objectAllocator.deallocate(objects, capacity);
......
/*
* 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 <stddef.h>
#include <functional>
#include <embb/base/mutex.h>
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<typename Key, typename Value>
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<Key, Value>* const & left,
ChromaticTreeNode<Key, Value>* 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<Key, Value>*& GetLeft();
/**
* Accessor for the right child pointer.
*
* \return Reference to the right child pointer
*/
ChromaticTreeNode<Key, Value>*& GetRight();
private:
const Key key_; /**< Stored key */
const Value value_; /**< Stored value */
const int weight_; /**< Weight of the node */
ChromaticTreeNode<Key, Value>* left_; /**< Pointer to left child node */
ChromaticTreeNode<Key, Value>* 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 <tt>(rhs < lhs)</tt> holds
* \tparam NodePool The object pool type used for allocation/deallocation
* of tree nodes.
*/
template<typename Key,
typename Value,
typename Compare = ::std::less<Key>,
typename NodePool = ObjectPool<internal::ChromaticTreeNode<Key, Value>,
LockFreeTreeValuePool<bool, false> >
>
class ChromaticTree {
public:
/**
* Creates a new tree with given capacity.
*
* \memory Allocates <tt>(2 * capacity + 7)</tt> tree nodes each of size
* <tt>sizeof(internal::ChromaticTreeNode<Key, Value>)</tt>.
*
* \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 <tt>Key()</tt>
* \param[IN] undefined_value Object of type \c Value to be used as a dummy
* value. Defaults to <tt>Value()</tt>
* \param[IN] compare Custom comparator object for managed keys.
* Defaults to <tt>Compare()</tt>
*
* \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<Key, Value> Node;
/**
* Typedef for a pointer to a node of the tree.
*/
typedef internal::ChromaticTreeNode<Key, Value>* 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<ReadWriteLockReader> ReaderLockGuard;
typedef embb::base::LockGuard<ReadWriteLockWriter> WriterLockGuard;
embb::base::ReadWriteLock readwrite_lock_;
};
} // namespace containers
} // namespace embb
#include <embb/containers/internal/lock_free_chromatic_tree-inl.h>
#endif // EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_H_
...@@ -180,6 +180,11 @@ class ObjectPool { ...@@ -180,6 +180,11 @@ class ObjectPool {
Type* Allocate(Param1 const& param1, Param2 const& param2, Type* Allocate(Param1 const& param1, Param2 const& param2,
Param3 const& param3, Param4 const& param4); Param3 const& param3, Param4 const& param4);
template<typename Param1, typename Param2, typename Param3, typename Param4,
typename Param5>
Type* Allocate(Param1 const& param1, Param2 const& param2,
Param3 const& param3, Param4 const& param4, Param5 const& param5);
#endif #endif
}; };
} // namespace containers } // namespace containers
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <embb/containers/object_pool.h> #include <embb/containers/object_pool.h>
#include <embb/containers/lock_free_stack.h> #include <embb/containers/lock_free_stack.h>
#include <embb/containers/lock_free_mpmc_queue.h> #include <embb/containers/lock_free_mpmc_queue.h>
#include <embb/containers/lock_free_chromatic_tree.h>
#include <embb/base/c/memory_allocation.h> #include <embb/base/c/memory_allocation.h>
#include <partest/partest.h> #include <partest/partest.h>
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
#include "./stack_test.h" #include "./stack_test.h"
#include "./hazard_pointer_test.h" #include "./hazard_pointer_test.h"
#include "./object_pool_test.h" #include "./object_pool_test.h"
#include "./tree_test.h"
#define COMMA , #define COMMA ,
...@@ -50,11 +52,13 @@ using embb::containers::LockFreeMPMCQueue; ...@@ -50,11 +52,13 @@ using embb::containers::LockFreeMPMCQueue;
using embb::containers::LockFreeStack; using embb::containers::LockFreeStack;
using embb::containers::LockFreeTreeValuePool; using embb::containers::LockFreeTreeValuePool;
using embb::containers::WaitFreeArrayValuePool; using embb::containers::WaitFreeArrayValuePool;
using embb::containers::ChromaticTree;
using embb::containers::test::PoolTest; using embb::containers::test::PoolTest;
using embb::containers::test::HazardPointerTest; using embb::containers::test::HazardPointerTest;
using embb::containers::test::QueueTest; using embb::containers::test::QueueTest;
using embb::containers::test::StackTest; using embb::containers::test::StackTest;
using embb::containers::test::ObjectPoolTest; using embb::containers::test::ObjectPoolTest;
using embb::containers::test::TreeTest;
PT_MAIN("Data Structures C++") { PT_MAIN("Data Structures C++") {
unsigned int max_threads = static_cast<unsigned int>( unsigned int max_threads = static_cast<unsigned int>(
...@@ -70,6 +74,7 @@ PT_MAIN("Data Structures C++") { ...@@ -70,6 +74,7 @@ PT_MAIN("Data Structures C++") {
PT_RUN(StackTest< LockFreeStack<int> >); PT_RUN(StackTest< LockFreeStack<int> >);
PT_RUN(ObjectPoolTest< LockFreeTreeValuePool<bool COMMA false > >); PT_RUN(ObjectPoolTest< LockFreeTreeValuePool<bool COMMA false > >);
PT_RUN(ObjectPoolTest< WaitFreeArrayValuePool<bool COMMA false> >); PT_RUN(ObjectPoolTest< WaitFreeArrayValuePool<bool COMMA false> >);
PT_RUN(TreeTest< ChromaticTree<size_t COMMA int> >);
PT_EXPECT(embb_get_bytes_allocated() == 0); PT_EXPECT(embb_get_bytes_allocated() == 0);
} }
/*
* 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 <utility>
#include <vector>
#include <algorithm>
#include "tree_test.h"
namespace embb {
namespace containers {
namespace test {
template<typename Tree>
TreeTest<Tree>::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<typename Tree>
TreeTest<Tree>::Worker::
Worker(Tree& tree, size_t thread_id, int num_elements)
: tree_(tree), thread_id_(thread_id), num_elements_(num_elements) {}
template<typename Tree>
void TreeTest<Tree>::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<typename Tree>
void TreeTest<Tree>::
TreeTestSingleThreadInsertDelete_Pre() {
tree_ = new Tree(TREE_CAPACITY);
}
template<typename Tree>
void TreeTest<Tree>::
TreeTestSingleThreadInsertDelete_ThreadMethod() {
size_t thread_id = partest::TestSuite::GetCurrentThreadID();
Worker worker(*tree_, thread_id, TREE_CAPACITY);
worker.Run();
}
template<typename Tree>
void TreeTest<Tree>::
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<typename Tree>
void TreeTest<Tree>::
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_
/*
* 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<typename Tree>
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<Key, Value> Element;
typedef ::std::vector<Element> 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_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment