mirror of
https://github.com/nasa/fprime.git
synced 2025-12-10 00:44:37 -06:00
* Revise RedBlackTree impl docs * Revise RedBlackTree impl docs * Revise RedBlackTree impl docs * Revise RedBlackTree impl docs * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl docs * Revise RedBlackTree impl * Revise RedBlackTree impl * Fix typo * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl docs * Revise RedBlackTree impl docs * Revise RedBlackTree impl * Revise RedBlackTreeImpl docs * Revise Fw/DataStructures Reformat code * Revise Fw/DataStructures Fix compile errors on Linux * Revise Fw/DataStructures Fix compile errors on Linux * Revise Fw/DataStructures Fix compile errors on Linux * Revise Fw/DataStructures Fix compile errors on Linux * Fix comments * Revise Fw/DataStructures Fix compile errors on Linux * Revise ArrayMap docs * Remove helper scripts * Revise tests for Fw/DataStructures * Fix spelling * Fix Markdown link * Fix uninitialized variable in test * Fix uninitialized variable in test * Fix "spelling" Why is the spelling check enforcing arbitrary rules of style? * Fix comments * Revise RedBlackTree impl docs * Start adding RedBlackTree impl * Revise tests for ArraySetOrMapImpl * Revise RedBlackTree impl * Revise comment * Revise comment * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise ArraySetOrMap impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Add RedBlackTree impl tester * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Fix comments * Revise RedBlackTree impl * Fix comments * Revise comments * Revise comments * Revise comments * Revise statement order for clarity * Revise unit tests for RedBlackTree impl * Revise RedBlackTree impl tests * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Add build and clean scripts Working around regressions in the F Prime build system * Revise build Fix warnings * Revise RedBlackTree impl and tests * Revise tests for RedBlackTree impl * Revise RedBlackTree impl and tests * Revise RedBlackTree tests Remove debug print statements * Revise RedBlackTree impl tester * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise build script * Revise RedBlackTree tests * Revise RedBlackTree tests * Revise RedBlackTree tests * Revise RedBlackTree tests * Revise RedBlackTree tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl test * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise comment * Revise RedBlackTree impl and tests * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl * Revise RedBlackTree impl tests * Revise RedBlackTree impl tests * Revise RedBlackTree impl * Revise RedBlackTree impl tests * Revise formatting * Format code * Revise docs * Revise docs for Fw/DataStructures * Revise Array and ExternalArray Add static assertions * Revise FifoQueue and Stack Add static assertions * Revise ArraySet and ArrayMap Add static assertions * Revise docs for ExternalRedBlackTreeMap * Revise docs for ExternalRedBlackTreeSet * Revise docs for RedBlackTreeMap * Revise docs for RedBlackTreeSet * Revise ExternalRedBlackTreeMap tests * Refactor ExternalStackTester * Revise ArrayMap tests * Add RedBlackTreeMap * Revise RedBlackTreeMap tests * Revise RedBlackTreeMap * Add ExternalRedBlackTreeSet * Add missing file * Revise SetConstIterator * Revise ExternalRedBlackTreeSet tests * Revise ExternalRedBlackTreeSet tests * Revise ExternalRedBlackTreeSet tests * Revise ExternalRedBlackTreeSet tests * Revise ExternalRedBlackTreeSet tests * Revise ExternalRedBlackTree tests * Revise ExternalArraySet tests * Revise ExternalArraySet tests * Add RedBlackTreeSet * Revise RedBlackTreeSet tests * Refactor ArraySetTest * Revise RedBlackTreeSetOrMapImpl docs * Revise array initialization * Revise comments * Revise Array initialization * Revise Array design and implementation * Revert changes to Fw/DataStructures * Revise Array * Revise Array * Revise Array * Fix formatting * Add SizedContainer base class * Revise StackBase Make it inherit from SizedContainer Revise stack tests * Revise MapBase Make it inherit from SizedContainer Revise tests * Revise SetBase Make it inherit from SizedContainer Revise tests * Revise DataStructures design Add SizedContainer * Revise SDD for DataStructures * Revise DataStructures design * Revise DataStructures design * Revise DataStructures design * Revise DataStructures design * Fix spelling * Revise zero-arg constructor for Array * Revise Array interface Make it consistent with the arrays generated by FPP * Fix to assertion * Format code * Fix spelling * Fix spelling * Add -Wno-comment to suppress warnings for now * Revise comments * Revise diagrams * Fix comment warnings on gcc * Eliminate tabs * Remove utility scripts * Revise placement of break statements * Rename function getParentDirection --> getDirectionFromParent * Add comment * Add svg diagram * Add svg diagram * Add svg files * Revise diagram * Replace png with svg * Replace png with svg * Replace png with svg * Revise comment * Revise SDD for red-black tree * Revise SDD for red-black tree
246 lines
9.3 KiB
C++
246 lines
9.3 KiB
C++
// ======================================================================
|
|
// \title RedBlackTreeSetOrMapImplTester.hpp
|
|
// \author bocchino
|
|
// \brief Class template for access to RedBlackTreeSetOrMapImpl members
|
|
// ======================================================================
|
|
|
|
#ifndef Fw_RedBlackTreeSetOrMapImplTester_HPP
|
|
#define Fw_RedBlackTreeSetOrMapImplTester_HPP
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <ostream>
|
|
|
|
#include "Fw/DataStructures/RedBlackTreeSetOrMapImpl.hpp"
|
|
#include "STest/STest/Pick/Pick.hpp"
|
|
|
|
namespace Fw {
|
|
|
|
template <typename KE, typename VN>
|
|
class RedBlackTreeSetOrMapImplTester {
|
|
public:
|
|
using Impl = RedBlackTreeSetOrMapImpl<KE, VN>;
|
|
|
|
using Color = typename Impl::Color;
|
|
|
|
using Direction = typename Impl::Direction;
|
|
|
|
using FreeNodes = typename Impl::FreeNodes;
|
|
|
|
using Index = typename Impl::Index;
|
|
|
|
using Node = typename Impl::Node;
|
|
|
|
using Nodes = typename Impl::Nodes;
|
|
|
|
RedBlackTreeSetOrMapImplTester<KE, VN>(const Impl& impl) : m_impl(impl) {
|
|
const auto capacity = this->m_impl.getCapacity();
|
|
this->blackHeights.setStorage(new FwSizeType[capacity], capacity);
|
|
}
|
|
|
|
~RedBlackTreeSetOrMapImplTester<KE, VN>() {
|
|
auto* const elements = this->blackHeights.getElements();
|
|
if (elements != nullptr) {
|
|
delete[] elements;
|
|
}
|
|
}
|
|
|
|
const Nodes& getNodes() const { return this->m_impl.m_nodes; }
|
|
|
|
const FreeNodes& getFreeNodes() const { return this->m_impl.m_freeNodes; }
|
|
|
|
Index getRoot() const { return this->m_impl.m_root; }
|
|
|
|
// Check properties of the tree
|
|
void checkProperties() {
|
|
this->checkBstProperty();
|
|
this->checkRbtProperties();
|
|
}
|
|
|
|
// Check the BST property of the tree
|
|
void checkBstProperty() const {
|
|
const auto capacity = this->m_impl.getCapacity();
|
|
auto it = this->m_impl.begin();
|
|
FwSizeType size = 0;
|
|
for (FwSizeType i = 0; i < capacity; i++) {
|
|
if (!it.isInRange()) {
|
|
break;
|
|
}
|
|
const KE key1 = it.getEntry().getKey();
|
|
size++;
|
|
it.increment();
|
|
if (!it.isInRange()) {
|
|
break;
|
|
}
|
|
const KE key2 = it.getEntry().getKey();
|
|
ASSERT_LT(key1, key2);
|
|
}
|
|
ASSERT_EQ(size, this->m_impl.getSize());
|
|
}
|
|
|
|
// Check the red-black tree properties of the tree. Return the black height.
|
|
void checkRbtProperties() {
|
|
const auto& nodes = this->m_impl.m_nodes;
|
|
auto node = this->m_impl.getOuterNodeUnder(this->m_impl.m_root, Direction::LEFT);
|
|
const auto capacity = this->m_impl.getCapacity();
|
|
bool done = (capacity > 0);
|
|
for (FwSizeType i = 0; i < capacity; i++) {
|
|
if (node == Node::NONE) {
|
|
done = true;
|
|
break;
|
|
}
|
|
const auto rightChild = nodes[node].getChild(Direction::RIGHT);
|
|
if (rightChild != Node::NONE) {
|
|
// There is a right child. Go to the leftmost node under that child.
|
|
node = this->m_impl.getOuterNodeUnder(rightChild, Direction::LEFT);
|
|
} else {
|
|
// There is no right child. Go upwards until we pass through a left child
|
|
// or we hit the root.
|
|
for (FwSizeType j = 0; j < capacity; j++) {
|
|
this->checkForRedViolation(node);
|
|
this->updateBlackHeight(node);
|
|
const auto previousNode = node;
|
|
node = nodes[node].m_parent;
|
|
if ((node == Node::NONE) or (nodes[node].getChild(Direction::LEFT) == previousNode)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ASSERT_TRUE(done);
|
|
}
|
|
|
|
// Get the black height of a node
|
|
FwSizeType getBlackHeight(Index node) const { return (node == Node::NONE) ? 1 : this->blackHeights[node]; }
|
|
|
|
// Check for a red violation at a node
|
|
void checkForRedViolation(Index node) const {
|
|
if (this->m_impl.getNodeColor(node) == Color::RED) {
|
|
const auto& nodes = this->m_impl.m_nodes;
|
|
const auto leftChild = nodes[node].getChild(Direction::LEFT);
|
|
ASSERT_NE(this->m_impl.getNodeColor(leftChild), Color::RED)
|
|
<< "Red child violation at left child\n"
|
|
<< " node index is " << node << "\n"
|
|
<< " node key is " << nodes[node].m_entry.getKeyOrElement() << "\n"
|
|
<< " left child index is " << leftChild << "\n"
|
|
<< " left child key is " << nodes[leftChild].m_entry.getKeyOrElement() << "\n";
|
|
const auto rightChild = nodes[node].getChild(Direction::RIGHT);
|
|
ASSERT_NE(this->m_impl.getNodeColor(rightChild), Color::RED)
|
|
<< "Red child violation at right child\n"
|
|
<< " node index is " << node << "\n"
|
|
<< " node key is " << nodes[node].m_entry.getKeyOrElement() << "\n"
|
|
<< " right child index is " << rightChild << "\n"
|
|
<< " right child key is " << nodes[rightChild].m_entry.getKeyOrElement() << "\n";
|
|
}
|
|
}
|
|
|
|
// Update the black height of a node, after visiting all its descendants.
|
|
// Check for a black height violation.
|
|
void updateBlackHeight(Index node) {
|
|
const auto& nodes = this->m_impl.m_nodes;
|
|
if (node != Node::NONE) {
|
|
const auto leftChild = nodes[node].getChild(Direction::LEFT);
|
|
const auto leftHeight = getBlackHeight(leftChild);
|
|
const auto rightChild = nodes[node].getChild(Direction::RIGHT);
|
|
const auto rightHeight = getBlackHeight(rightChild);
|
|
ASSERT_EQ(leftHeight, rightHeight) << "Black height violation at node " << node << "\n"
|
|
<< " left child index is " << leftChild << "\n"
|
|
<< " right child index is " << rightChild << "\n";
|
|
const FwSizeType nodeHeight = (this->m_impl.getNodeColor(node) == Color::BLACK) ? 1 : 0;
|
|
const FwSizeType blackHeight = leftHeight + nodeHeight;
|
|
this->blackHeights[node] = blackHeight;
|
|
}
|
|
}
|
|
|
|
// Print the black height
|
|
void printBlackHeight() { std::cout << "black height is " << getBlackHeight(this->m_impl.m_root) << "\n"; }
|
|
|
|
// Print the tree
|
|
void printTree() {
|
|
auto node = this->m_impl.m_root;
|
|
auto child = Node::NONE;
|
|
const auto capacity = this->m_impl.getCapacity();
|
|
I32 indent = 0;
|
|
constexpr I32 indentIncrement = 2;
|
|
const FwSizeType loopBound = 3 * capacity;
|
|
for (FwSizeType i = 0; i < loopBound; i++) {
|
|
if (node == Node::NONE) {
|
|
break;
|
|
}
|
|
const auto& nodeObject = this->m_impl.m_nodes[node];
|
|
const auto leftChild = nodeObject.m_left;
|
|
const auto rightChild = nodeObject.m_right;
|
|
if (child == Node::NONE) {
|
|
this->printNode(indent, node);
|
|
if (leftChild != Node::NONE) {
|
|
indent += indentIncrement;
|
|
node = leftChild;
|
|
} else if (rightChild != Node::NONE) {
|
|
indent += indentIncrement;
|
|
node = rightChild;
|
|
} else {
|
|
indent -= indentIncrement;
|
|
child = node;
|
|
node = nodeObject.m_parent;
|
|
}
|
|
} else if ((child == leftChild) && (rightChild != Node::NONE)) {
|
|
indent += indentIncrement;
|
|
node = rightChild;
|
|
child = Node::NONE;
|
|
} else {
|
|
indent -= indentIncrement;
|
|
child = node;
|
|
node = nodeObject.m_parent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Print a node
|
|
void printNode(I32 indent, Index node) {
|
|
for (I32 i = 0; i < indent; i++) {
|
|
std::cout << " ";
|
|
}
|
|
if (node == Node::NONE) {
|
|
std::cout << "NONE\n";
|
|
} else {
|
|
const auto& nodeObject = this->m_impl.m_nodes[node];
|
|
const auto parent = nodeObject.m_parent;
|
|
if (parent != Node::NONE) {
|
|
const auto parentDirection = this->m_impl.getDirectionFromParent(node);
|
|
std::cout << directionToString(parentDirection) << " ";
|
|
}
|
|
Fw::String parentStr;
|
|
indexToString(parent, parentStr);
|
|
std::cout << "Node " << node << " { parent=" << parentStr.toChar()
|
|
<< ", key=" << nodeObject.m_entry.getKeyOrElement()
|
|
<< ", value=" << nodeObject.m_entry.getValueOrNil()
|
|
<< ", color=" << colorToString(nodeObject.m_color) << " }\n";
|
|
}
|
|
}
|
|
|
|
// Convert an index to a string
|
|
void indexToString(Index node, Fw::StringBase& str) {
|
|
if (node == Node::NONE) {
|
|
str = "NONE";
|
|
} else {
|
|
str.format("%" PRI_FwSizeType, node);
|
|
}
|
|
}
|
|
|
|
// Convert a color to a string
|
|
static const char* colorToString(Color color) { return (color == Color::RED) ? "RED" : "BLACK"; }
|
|
|
|
// Convert a direction to a string
|
|
static const char* directionToString(Direction direction) {
|
|
return (direction == Direction::LEFT) ? "LEFT" : "RIGHT";
|
|
}
|
|
|
|
private:
|
|
const Impl& m_impl;
|
|
// Array for storing black heights
|
|
ExternalArray<FwSizeType> blackHeights = {};
|
|
};
|
|
|
|
} // namespace Fw
|
|
|
|
#endif
|