mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Created multiset_base.h and derived imultiset from it.
Moved non-type code to base classes.
This commit is contained in:
parent
5794aebd8b
commit
b3b9426a69
@ -666,9 +666,9 @@ namespace etl
|
||||
else
|
||||
{
|
||||
#ifdef ETL_THROW_EXCEPTIONS
|
||||
throw map_full();
|
||||
throw multimap_full();
|
||||
#else
|
||||
error_handler::error(map_full());
|
||||
error_handler::error(multimap_full());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
418
imultiset.h
418
imultiset.h
@ -37,7 +37,7 @@ SOFTWARE.
|
||||
#include <stddef.h>
|
||||
|
||||
#include "nullptr.h"
|
||||
#include "set_base.h"
|
||||
#include "multiset_base.h"
|
||||
#include "type_traits.h"
|
||||
#include "parameter_type.h"
|
||||
#include "pool.h"
|
||||
@ -53,7 +53,7 @@ namespace etl
|
||||
///\ingroup set
|
||||
//***************************************************************************
|
||||
template <typename T, typename TCompare>
|
||||
class imultiset : public set_base
|
||||
class imultiset : public multiset_base
|
||||
{
|
||||
public:
|
||||
|
||||
@ -88,41 +88,6 @@ namespace etl
|
||||
};
|
||||
|
||||
protected:
|
||||
static const uint8_t kLeft = 0;
|
||||
static const uint8_t kRight = 1;
|
||||
static const uint8_t kNeither = 2;
|
||||
|
||||
//*************************************************************************
|
||||
/// The node element in the multiset.
|
||||
//*************************************************************************
|
||||
struct Node
|
||||
{
|
||||
//***********************************************************************
|
||||
/// Constructor
|
||||
//***********************************************************************
|
||||
Node() :
|
||||
weight(kNeither),
|
||||
dir(kNeither)
|
||||
{
|
||||
}
|
||||
|
||||
//***********************************************************************
|
||||
/// Marks the node as a leaf.
|
||||
//***********************************************************************
|
||||
void mark_as_leaf()
|
||||
{
|
||||
weight = kNeither;
|
||||
dir = kNeither;
|
||||
parent = nullptr;
|
||||
children[0] = nullptr;
|
||||
children[1] = nullptr;
|
||||
}
|
||||
|
||||
Node* parent;
|
||||
Node* children[2];
|
||||
uint8_t weight;
|
||||
uint8_t dir;
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
/// The data node element in the multiset.
|
||||
@ -161,9 +126,6 @@ namespace etl
|
||||
/// The pool of data nodes used in the multiset.
|
||||
ipool<Data_Node>* p_node_pool;
|
||||
|
||||
/// The node that acts as the multiset root.
|
||||
Node* root_node;
|
||||
|
||||
//*************************************************************************
|
||||
/// Downcast a Node* to a Data_Node*
|
||||
//*************************************************************************
|
||||
@ -685,9 +647,9 @@ namespace etl
|
||||
else
|
||||
{
|
||||
#ifdef ETL_THROW_EXCEPTIONS
|
||||
throw set_full();
|
||||
throw multiset_full();
|
||||
#else
|
||||
error_handler::error(set_full());
|
||||
error_handler::error(multiset_full());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -790,9 +752,8 @@ namespace etl
|
||||
/// Constructor.
|
||||
//*************************************************************************
|
||||
imultiset(ipool<Data_Node>& node_pool, size_t max_size_)
|
||||
: set_base(max_size_)
|
||||
: multiset_base(max_size_)
|
||||
, p_node_pool(&node_pool)
|
||||
, root_node(nullptr)
|
||||
{
|
||||
initialise();
|
||||
}
|
||||
@ -829,87 +790,6 @@ namespace etl
|
||||
root_node = nullptr;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Attach the provided node to the position provided
|
||||
//*************************************************************************
|
||||
void attach_node(Node* parent, Node*& position, Data_Node& node)
|
||||
{
|
||||
// Mark new node as leaf on attach to tree at position provided
|
||||
node.mark_as_leaf();
|
||||
|
||||
// Keep track of this node's parent
|
||||
node.parent = parent;
|
||||
|
||||
// Add the node here
|
||||
position = &node;
|
||||
|
||||
// One more.
|
||||
++current_size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Balance the critical node at the position provided as needed
|
||||
//*************************************************************************
|
||||
void balance_node(Node*& critical_node)
|
||||
{
|
||||
// Step 1: Update weights for all children of the critical node up to the
|
||||
// newly inserted node. This step is costly (in terms of traversing nodes
|
||||
// multiple times during insertion) but doesn't require as much recursion
|
||||
Node* weight_node = critical_node->children[critical_node->dir];
|
||||
while (weight_node)
|
||||
{
|
||||
// Keep going until we reach a terminal node (dir == kNeither)
|
||||
if (kNeither != weight_node->dir)
|
||||
{
|
||||
// Does this insert balance the previous weight factor value?
|
||||
if (weight_node->weight == 1 - weight_node->dir)
|
||||
{
|
||||
weight_node->weight = kNeither;
|
||||
}
|
||||
else
|
||||
{
|
||||
weight_node->weight = weight_node->dir;
|
||||
}
|
||||
|
||||
// Update weight factor node to point to next node
|
||||
weight_node = weight_node->children[weight_node->dir];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop loop, terminal node found
|
||||
break;
|
||||
}
|
||||
} // while(weight_node)
|
||||
|
||||
// Step 2: Update weight for critical_node or rotate tree to balance node
|
||||
if (kNeither == critical_node->weight)
|
||||
{
|
||||
critical_node->weight = critical_node->dir;
|
||||
}
|
||||
// If direction is different than weight, then it will now be balanced
|
||||
else if (critical_node->dir != critical_node->weight)
|
||||
{
|
||||
critical_node->weight = kNeither;
|
||||
}
|
||||
// Rotate is required to balance the tree at the critical node
|
||||
else
|
||||
{
|
||||
// If critical node matches child node direction then perform a two
|
||||
// node rotate in the direction of the critical node
|
||||
if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
|
||||
{
|
||||
rotate_2node(critical_node, critical_node->dir);
|
||||
}
|
||||
// Otherwise perform a three node rotation in the direction of the
|
||||
// critical node
|
||||
else
|
||||
{
|
||||
rotate_3node(critical_node, critical_node->dir,
|
||||
critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Count the nodes that match the key provided
|
||||
//*************************************************************************
|
||||
@ -942,39 +822,6 @@ namespace etl
|
||||
return result;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Detach the node at the position provided
|
||||
//*************************************************************************
|
||||
void detach_node(Node*& position, Node*& replacement)
|
||||
{
|
||||
// Make temporary copy of actual nodes involved because we might lose
|
||||
// their references in the process (e.g. position is the same as
|
||||
// replacement or replacement is a child of position)
|
||||
Node* detached = position;
|
||||
Node* swap = replacement;
|
||||
|
||||
// Update current position to point to swap (replacement) node first
|
||||
position = swap;
|
||||
|
||||
// Update replacement node to point to child in opposite direction
|
||||
// otherwise we might lose the other child of the swap node
|
||||
replacement = swap->children[1 - swap->dir];
|
||||
|
||||
// Point swap node to detached node's parent, children and weight
|
||||
swap->parent = detached->parent;
|
||||
swap->children[kLeft] = detached->children[kLeft];
|
||||
swap->children[kRight] = detached->children[kRight];
|
||||
if (swap->children[kLeft])
|
||||
{
|
||||
swap->children[kLeft]->parent = swap;
|
||||
}
|
||||
if (swap->children[kRight])
|
||||
{
|
||||
swap->children[kRight]->parent = swap;
|
||||
}
|
||||
swap->weight = detached->weight;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the value matching the node provided
|
||||
//*************************************************************************
|
||||
@ -1041,23 +888,6 @@ namespace etl
|
||||
return found;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the node whose key would go before all the other keys from the
|
||||
/// position provided
|
||||
//*************************************************************************
|
||||
Node* find_limit_node(Node* position, const int8_t dir) const
|
||||
{
|
||||
// Something at this position and in the direction specified? keep going
|
||||
Node* limit_node = position;
|
||||
while (limit_node && limit_node->children[dir])
|
||||
{
|
||||
limit_node = limit_node->children[dir];
|
||||
}
|
||||
|
||||
// Return the limit node position found
|
||||
return limit_node;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the node whose key is not considered to go before the key provided
|
||||
//*************************************************************************
|
||||
@ -1244,146 +1074,6 @@ namespace etl
|
||||
return found;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the next node in sequence from the node provided
|
||||
//*************************************************************************
|
||||
void next_node(Node*& position) const
|
||||
{
|
||||
if (position)
|
||||
{
|
||||
// Is there a tree on the right? then find the minimum of that tree
|
||||
if (position->children[kRight])
|
||||
{
|
||||
// Return minimum node found
|
||||
position = find_limit_node(position->children[kRight], kLeft);
|
||||
}
|
||||
// Otherwise find the parent of this node
|
||||
else
|
||||
{
|
||||
// Start with current position as parent
|
||||
Node* parent = position;
|
||||
do {
|
||||
// Update current position as previous parent
|
||||
position = parent;
|
||||
// Find parent of current position
|
||||
parent = position->parent; // find_parent_node(root_node, position);
|
||||
// Repeat while previous position was on right side of parent tree
|
||||
} while (parent && parent->children[kRight] == position);
|
||||
|
||||
// Set parent node as the next position
|
||||
position = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the next node in sequence from the node provided
|
||||
//*************************************************************************
|
||||
void next_node(const Node*& position) const
|
||||
{
|
||||
if (position)
|
||||
{
|
||||
// Is there a tree on the right? then find the minimum of that tree
|
||||
if (position->children[kRight])
|
||||
{
|
||||
// Return minimum node found
|
||||
position = find_limit_node(position->children[kRight], kLeft);
|
||||
}
|
||||
// Otherwise find the parent of this node
|
||||
else
|
||||
{
|
||||
// Start with current position as parent
|
||||
const Node* parent = position;
|
||||
do {
|
||||
// Update current position as previous parent
|
||||
position = parent;
|
||||
// Find parent of current position
|
||||
parent = position->parent;
|
||||
// Repeat while previous position was on right side of parent tree
|
||||
} while (parent && parent->children[kRight] == position);
|
||||
|
||||
// Set parent node as the next position
|
||||
position = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the previous node in sequence from the node provided
|
||||
//*************************************************************************
|
||||
void prev_node(Node*& position) const
|
||||
{
|
||||
// If starting at the terminal end, the previous node is the maximum node
|
||||
// from the root
|
||||
if (!position)
|
||||
{
|
||||
position = find_limit_node(root_node, kRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is there a tree on the left? then find the maximum of that tree
|
||||
if (position->children[kLeft])
|
||||
{
|
||||
// Return maximum node found
|
||||
position = find_limit_node(position->children[kLeft], kRight);
|
||||
}
|
||||
// Otherwise find the parent of this node
|
||||
else
|
||||
{
|
||||
// Start with current position as parent
|
||||
Node* parent = position;
|
||||
do {
|
||||
// Update current position as previous parent
|
||||
position = parent;
|
||||
// Find parent of current position
|
||||
parent = position->parent;
|
||||
// Repeat while previous position was on left side of parent tree
|
||||
} while (parent && parent->children[kLeft] == position);
|
||||
|
||||
// Set parent node as the next position
|
||||
position = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the previous node in sequence from the node provided
|
||||
//*************************************************************************
|
||||
void prev_node(const Node*& position) const
|
||||
{
|
||||
// If starting at the terminal end, the previous node is the maximum node
|
||||
// from the root
|
||||
if (!position)
|
||||
{
|
||||
position = find_limit_node(root_node, kRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Is there a tree on the left? then find the maximum of that tree
|
||||
if (position->children[kLeft])
|
||||
{
|
||||
// Return maximum node found
|
||||
position = find_limit_node(position->children[kLeft], kRight);
|
||||
}
|
||||
// Otherwise find the parent of this node
|
||||
else
|
||||
{
|
||||
// Start with current position as parent
|
||||
const Node* parent = position;
|
||||
do {
|
||||
// Update current position as previous parent
|
||||
position = parent;
|
||||
// Find parent of current position
|
||||
parent = position->parent;
|
||||
// Repeat while previous position was on left side of parent tree
|
||||
} while (parent && parent->children[kLeft] == position);
|
||||
|
||||
// Set parent node as the next position
|
||||
position = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Remove the node specified from somewhere starting at the position
|
||||
/// provided
|
||||
@ -1618,104 +1308,6 @@ namespace etl
|
||||
destroy_data_node(data_node);
|
||||
} // if(found)
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Rotate two nodes at the position provided the to balance the tree
|
||||
//*************************************************************************
|
||||
void rotate_2node(Node*& position, uint8_t dir)
|
||||
{
|
||||
// A C A B
|
||||
// B C -> A E OR B C -> D A
|
||||
// D E B D D E E C
|
||||
// C (new position) becomes the root
|
||||
// A (position) takes ownership of D as its children[kRight] child
|
||||
// C (new position) takes ownership of A as its left child
|
||||
// OR
|
||||
// B (new position) becomes the root
|
||||
// A (position) takes ownership of E as its left child
|
||||
// B (new position) takes ownership of A as its right child
|
||||
|
||||
// Capture new root (either B or C depending on dir) and its parent
|
||||
Node* new_root = position->children[dir];
|
||||
|
||||
// Replace position's previous child with new root's other child
|
||||
position->children[dir] = new_root->children[1 - dir];
|
||||
// Update new root's other child parent pointer
|
||||
if (position->children[dir])
|
||||
{
|
||||
position->children[dir]->parent = position;
|
||||
}
|
||||
|
||||
// New root's parent becomes current position's parent
|
||||
new_root->parent = position->parent;
|
||||
new_root->children[1 - dir] = position;
|
||||
new_root->dir = 1 - dir;
|
||||
|
||||
// Clear weight factor from current position
|
||||
position->weight = kNeither;
|
||||
// Position's parent becomes new_root
|
||||
position->parent = new_root;
|
||||
position = new_root;
|
||||
// Clear weight factor from new root
|
||||
position->weight = kNeither;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Rotate three nodes at the position provided the to balance the tree
|
||||
//*************************************************************************
|
||||
void rotate_3node(Node*& position, uint8_t dir, uint8_t third)
|
||||
{
|
||||
// __A__ __E__ __A__ __D__
|
||||
// _B_ C -> B A OR B _C_ -> A C
|
||||
// D E D F G C D E B F G E
|
||||
// F G F G
|
||||
// E (new position) becomes the root
|
||||
// B (position) takes ownership of F as its left child
|
||||
// A takes ownership of G as its right child
|
||||
// OR
|
||||
// D (new position) becomes the root
|
||||
// A (position) takes ownership of F as its right child
|
||||
// C takes ownership of G as its left child
|
||||
|
||||
// Capture new root (either E or D depending on dir)
|
||||
Node* new_root = position->children[dir]->children[1 - dir];
|
||||
// Set weight factor for B or C based on F or G existing and being a different than dir
|
||||
position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
|
||||
|
||||
// Detach new root from its tree (replace with new roots child)
|
||||
position->children[dir]->children[1 - dir] = new_root->children[dir];
|
||||
// Update new roots child parent pointer
|
||||
if (new_root->children[dir])
|
||||
{
|
||||
new_root->children[dir]->parent = position->children[dir];
|
||||
}
|
||||
|
||||
// Attach current left tree to new root and update its parent
|
||||
new_root->children[dir] = position->children[dir];
|
||||
position->children[dir]->parent = new_root;
|
||||
|
||||
// Set weight factor for A based on F or G
|
||||
position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
|
||||
|
||||
// Move new root's right tree to current roots left tree
|
||||
position->children[dir] = new_root->children[1 - dir];
|
||||
if (new_root->children[1 - dir])
|
||||
{
|
||||
new_root->children[1 - dir]->parent = position;
|
||||
}
|
||||
|
||||
// Attach current root to new roots right tree and assume its parent
|
||||
new_root->parent = position->parent;
|
||||
new_root->children[1 - dir] = position;
|
||||
new_root->dir = 1 - dir;
|
||||
|
||||
// Update current position's parent and replace with new root
|
||||
position->parent = new_root;
|
||||
position = new_root;
|
||||
// Clear weight factor for new current position
|
||||
position->weight = kNeither;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
243
iset.h
243
iset.h
@ -88,39 +88,6 @@ namespace etl
|
||||
};
|
||||
|
||||
protected:
|
||||
static const uint8_t kLeft = 0;
|
||||
static const uint8_t kRight = 1;
|
||||
static const uint8_t kNeither = 2;
|
||||
|
||||
//*************************************************************************
|
||||
/// The node element in the set.
|
||||
//*************************************************************************
|
||||
struct Node
|
||||
{
|
||||
//***********************************************************************
|
||||
/// Constructor
|
||||
//***********************************************************************
|
||||
Node() :
|
||||
weight(kNeither),
|
||||
dir(kNeither)
|
||||
{
|
||||
}
|
||||
|
||||
//***********************************************************************
|
||||
/// Marks the node as a leaf.
|
||||
//***********************************************************************
|
||||
void mark_as_leaf()
|
||||
{
|
||||
weight = kNeither;
|
||||
dir = kNeither;
|
||||
children[0] = nullptr;
|
||||
children[1] = nullptr;
|
||||
}
|
||||
|
||||
Node* children[2];
|
||||
uint8_t weight;
|
||||
uint8_t dir;
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
/// The data node element in the set.
|
||||
@ -159,9 +126,6 @@ namespace etl
|
||||
/// The pool of data nodes used in the set.
|
||||
ipool<Data_Node>* p_node_pool;
|
||||
|
||||
/// The node that acts as the set root.
|
||||
Node* root_node;
|
||||
|
||||
//*************************************************************************
|
||||
/// Downcast a Node* to a Data_Node*
|
||||
//*************************************************************************
|
||||
@ -822,7 +786,6 @@ namespace etl
|
||||
iset(ipool<Data_Node>& node_pool, size_t max_size_)
|
||||
: set_base(max_size_)
|
||||
, p_node_pool(&node_pool)
|
||||
, root_node(nullptr)
|
||||
{
|
||||
initialise();
|
||||
}
|
||||
@ -859,108 +822,6 @@ namespace etl
|
||||
root_node = nullptr;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Attach the provided node to the position provided
|
||||
//*************************************************************************
|
||||
void attach_node(Node*& position, Data_Node& node)
|
||||
{
|
||||
// Mark new node as leaf on attach to tree at position provided
|
||||
node.mark_as_leaf();
|
||||
|
||||
// Add the node here
|
||||
position = &node;
|
||||
|
||||
// One more.
|
||||
++current_size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Balance the critical node at the position provided as needed
|
||||
//*************************************************************************
|
||||
void balance_node(Node*& critical_node)
|
||||
{
|
||||
// Step 1: Update weights for all children of the critical node up to the
|
||||
// newly inserted node. This step is costly (in terms of traversing nodes
|
||||
// multiple times during insertion) but doesn't require as much recursion
|
||||
Node* weight_node = critical_node->children[critical_node->dir];
|
||||
while (weight_node)
|
||||
{
|
||||
// Keep going until we reach a terminal node (dir == kNeither)
|
||||
if (kNeither != weight_node->dir)
|
||||
{
|
||||
// Does this insert balance the previous weight factor value?
|
||||
if (weight_node->weight == 1 - weight_node->dir)
|
||||
{
|
||||
weight_node->weight = kNeither;
|
||||
}
|
||||
else
|
||||
{
|
||||
weight_node->weight = weight_node->dir;
|
||||
}
|
||||
|
||||
// Update weight factor node to point to next node
|
||||
weight_node = weight_node->children[weight_node->dir];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop loop, terminal node found
|
||||
break;
|
||||
}
|
||||
} // while(weight_node)
|
||||
|
||||
// Step 2: Update weight for critical_node or rotate tree to balance node
|
||||
if (kNeither == critical_node->weight)
|
||||
{
|
||||
critical_node->weight = critical_node->dir;
|
||||
}
|
||||
// If direction is different than weight, then it will now be balanced
|
||||
else if (critical_node->dir != critical_node->weight)
|
||||
{
|
||||
critical_node->weight = kNeither;
|
||||
}
|
||||
// Rotate is required to balance the tree at the critical node
|
||||
else
|
||||
{
|
||||
// If critical node matches child node direction then perform a two
|
||||
// node rotate in the direction of the critical node
|
||||
if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
|
||||
{
|
||||
rotate_2node(critical_node, critical_node->dir);
|
||||
}
|
||||
// Otherwise perform a three node rotation in the direction of the
|
||||
// critical node
|
||||
else
|
||||
{
|
||||
rotate_3node(critical_node, critical_node->dir,
|
||||
critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Detach the node at the position provided
|
||||
//*************************************************************************
|
||||
void detach_node(Node*& position, Node*& replacement)
|
||||
{
|
||||
// Make temporary copy of actual nodes involved because we might lose
|
||||
// their references in the process (e.g. position is the same as
|
||||
// replacement or replacement is a child of position)
|
||||
Node* detached = position;
|
||||
Node* swap = replacement;
|
||||
|
||||
// Update current position to point to swap (replacement) node first
|
||||
position = swap;
|
||||
|
||||
// Update replacement node to point to child in opposite direction
|
||||
// otherwise we might lose the other child of the swap node
|
||||
replacement = swap->children[1 - swap->dir];
|
||||
|
||||
// Point swap node to detached node's children and weight
|
||||
swap->children[kLeft] = detached->children[kLeft];
|
||||
swap->children[kRight] = detached->children[kRight];
|
||||
swap->weight = detached->weight;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the value matching the node provided
|
||||
//*************************************************************************
|
||||
@ -1072,40 +933,6 @@ namespace etl
|
||||
return root_node;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the node whose key would go before all the other keys from the
|
||||
/// position provided
|
||||
//*************************************************************************
|
||||
Node* find_limit_node(Node* position, const int8_t dir) const
|
||||
{
|
||||
// Something at this position and in the direction specified? keep going
|
||||
Node* limit_node = position;
|
||||
while (limit_node && limit_node->children[dir])
|
||||
{
|
||||
limit_node = limit_node->children[dir];
|
||||
}
|
||||
|
||||
// Return the limit node position found
|
||||
return limit_node;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the node whose key would go before all the other keys from the
|
||||
/// position provided
|
||||
//*************************************************************************
|
||||
const Node* find_limit_node(const Node* position, const int8_t dir) const
|
||||
{
|
||||
// Something at this position and in the direction specified? keep going
|
||||
Node* limit_node = position;
|
||||
while (limit_node && limit_node->children[dir])
|
||||
{
|
||||
limit_node = limit_node->children[dir];
|
||||
}
|
||||
|
||||
// Return the limit node position found
|
||||
return limit_node;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the parent node that contains the node provided in its left or
|
||||
/// right tree
|
||||
@ -1722,76 +1549,6 @@ namespace etl
|
||||
// Return node found (might be nullptr)
|
||||
return found;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Rotate two nodes at the position provided the to balance the tree
|
||||
//*************************************************************************
|
||||
void rotate_2node(Node*& position, uint8_t dir)
|
||||
{
|
||||
// A C A B
|
||||
// B C -> A E OR B C -> D A
|
||||
// D E B D D E E C
|
||||
// C (new position) becomes the root
|
||||
// A (position) takes ownership of D as its children[kRight] child
|
||||
// C (new position) takes ownership of A as its left child
|
||||
// OR
|
||||
// B (new position) becomes the root
|
||||
// A (position) takes ownership of E as its left child
|
||||
// B (new position) takes ownership of A as its right child
|
||||
|
||||
// Capture new root
|
||||
Node* new_root = position->children[dir];
|
||||
// Replace position's previous child with new root's other child
|
||||
position->children[dir] = new_root->children[1 - dir];
|
||||
// New root now becomes parent of current position
|
||||
new_root->children[1 - dir] = position;
|
||||
// Clear weight factor from current position
|
||||
position->weight = kNeither;
|
||||
// Newly detached right now becomes current position
|
||||
position = new_root;
|
||||
// Clear weight factor from new root
|
||||
position->weight = kNeither;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Rotate three nodes at the position provided the to balance the tree
|
||||
//*************************************************************************
|
||||
void rotate_3node(Node*& position, uint8_t dir, uint8_t third)
|
||||
{
|
||||
// __A__ __E__ __A__ __D__
|
||||
// _B_ C -> B A OR B _C_ -> A C
|
||||
// D E D F G C D E B F G E
|
||||
// F G F G
|
||||
// E (new position) becomes the root
|
||||
// B (position) takes ownership of F as its left child
|
||||
// A takes ownership of G as its right child
|
||||
// OR
|
||||
// D (new position) becomes the root
|
||||
// A (position) takes ownership of F as its right child
|
||||
// C takes ownership of G as its left child
|
||||
|
||||
// Capture new root (either E or D depending on dir)
|
||||
Node* new_root = position->children[dir]->children[1 - dir];
|
||||
// Set weight factor for B or C based on F or G existing and being a different than dir
|
||||
position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
|
||||
|
||||
// Detach new root from its tree (replace with new roots child)
|
||||
position->children[dir]->children[1 - dir] =
|
||||
new_root->children[dir];
|
||||
// Attach current left tree to new root
|
||||
new_root->children[dir] = position->children[dir];
|
||||
// Set weight factor for A based on F or G
|
||||
position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
|
||||
|
||||
// Move new root's right tree to current roots left tree
|
||||
position->children[dir] = new_root->children[1 - dir];
|
||||
// Attach current root to new roots right tree
|
||||
new_root->children[1 - dir] = position;
|
||||
// Replace current position with new root
|
||||
position = new_root;
|
||||
// Clear weight factor for new current position
|
||||
position->weight = kNeither;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -27,8 +27,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#if !defined(__ETL_IN_IMAP_H__) && !defined(__ETL_IN_IMULTIMAP_H__)
|
||||
#error This header is a private element of etl::map, etl::multimap & etl::imap, etl::imultimap
|
||||
#if !defined(__ETL_IN_IMAP_H__)
|
||||
#error This header is a private element of etl::map & etl::imap
|
||||
#endif
|
||||
|
||||
#ifndef __ETL_MAP_BASE__
|
||||
|
||||
@ -43,11 +43,11 @@ namespace etl
|
||||
/// Exception for the map.
|
||||
///\ingroup map
|
||||
//***************************************************************************
|
||||
class map_exception : public exception
|
||||
class multimap_exception : public exception
|
||||
{
|
||||
public:
|
||||
|
||||
map_exception(const char* what)
|
||||
multimap_exception(const char* what)
|
||||
: exception(what)
|
||||
{
|
||||
}
|
||||
@ -57,12 +57,12 @@ namespace etl
|
||||
/// Full exception for the map.
|
||||
///\ingroup map
|
||||
//***************************************************************************
|
||||
class map_full : public map_exception
|
||||
class multimap_full : public multimap_exception
|
||||
{
|
||||
public:
|
||||
|
||||
map_full()
|
||||
: map_exception("map: full")
|
||||
multimap_full()
|
||||
: multimap_exception("multimap: full")
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -71,12 +71,12 @@ namespace etl
|
||||
/// Map out of bounds exception.
|
||||
///\ingroup map
|
||||
//***************************************************************************
|
||||
class map_out_of_bounds : public map_exception
|
||||
class multimap_out_of_bounds : public multimap_exception
|
||||
{
|
||||
public:
|
||||
|
||||
map_out_of_bounds()
|
||||
: map_exception("map: out of bounds")
|
||||
multimap_out_of_bounds()
|
||||
: multimap_exception("multimap: out of bounds")
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -85,12 +85,12 @@ namespace etl
|
||||
/// Iterator exception for the map.
|
||||
///\ingroup map
|
||||
//***************************************************************************
|
||||
class map_iterator : public map_exception
|
||||
class multimap_iterator : public multimap_exception
|
||||
{
|
||||
public:
|
||||
|
||||
map_iterator()
|
||||
: map_exception("map: iterator problem")
|
||||
multimap_iterator()
|
||||
: multimap_exception("multimap: iterator problem")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
249
set_base.h
249
set_base.h
@ -6,7 +6,7 @@ The MIT License(MIT)
|
||||
Embedded Template Library.
|
||||
https://github.com/ETLCPP/etl
|
||||
|
||||
Copyright(c) 2014 jwellbelove, rlindeman
|
||||
Copyright(c) 2015 jwellbelove, rlindeman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
@ -27,8 +27,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#if !defined(__ETL_IN_ISET_H__) && !defined(__ETL_IN_IMULTISET_H__)
|
||||
#error This header is a private element of etl::set, etl::multiset & etl::iset, etl::imultiset
|
||||
#if !defined(__ETL_IN_ISET_H__)
|
||||
#error This header is a private element of etl::set & etl::iset
|
||||
#endif
|
||||
|
||||
#ifndef __ETL_SET_BASE__
|
||||
@ -157,18 +157,261 @@ namespace etl
|
||||
|
||||
protected:
|
||||
|
||||
static const uint8_t kLeft = 0;
|
||||
static const uint8_t kRight = 1;
|
||||
static const uint8_t kNeither = 2;
|
||||
|
||||
//*************************************************************************
|
||||
/// The node element in the set.
|
||||
//*************************************************************************
|
||||
struct Node
|
||||
{
|
||||
//***********************************************************************
|
||||
/// Constructor
|
||||
//***********************************************************************
|
||||
Node() :
|
||||
weight(kNeither),
|
||||
dir(kNeither)
|
||||
{
|
||||
}
|
||||
|
||||
//***********************************************************************
|
||||
/// Marks the node as a leaf.
|
||||
//***********************************************************************
|
||||
void mark_as_leaf()
|
||||
{
|
||||
weight = kNeither;
|
||||
dir = kNeither;
|
||||
children[0] = nullptr;
|
||||
children[1] = nullptr;
|
||||
}
|
||||
|
||||
Node* children[2];
|
||||
uint8_t weight;
|
||||
uint8_t dir;
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
/// The constructor that is called from derived classes.
|
||||
//*************************************************************************
|
||||
set_base(size_type max_size)
|
||||
: current_size(0)
|
||||
, MAX_SIZE(max_size)
|
||||
, root_node(nullptr)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Attach the provided node to the position provided
|
||||
//*************************************************************************
|
||||
void attach_node(Node*& position, Node& node)
|
||||
{
|
||||
// Mark new node as leaf on attach to tree at position provided
|
||||
node.mark_as_leaf();
|
||||
|
||||
// Add the node here
|
||||
position = &node;
|
||||
|
||||
// One more.
|
||||
++current_size;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Detach the node at the position provided
|
||||
//*************************************************************************
|
||||
void detach_node(Node*& position, Node*& replacement)
|
||||
{
|
||||
// Make temporary copy of actual nodes involved because we might lose
|
||||
// their references in the process (e.g. position is the same as
|
||||
// replacement or replacement is a child of position)
|
||||
Node* detached = position;
|
||||
Node* swap = replacement;
|
||||
|
||||
// Update current position to point to swap (replacement) node first
|
||||
position = swap;
|
||||
|
||||
// Update replacement node to point to child in opposite direction
|
||||
// otherwise we might lose the other child of the swap node
|
||||
replacement = swap->children[1 - swap->dir];
|
||||
|
||||
// Point swap node to detached node's children and weight
|
||||
swap->children[kLeft] = detached->children[kLeft];
|
||||
swap->children[kRight] = detached->children[kRight];
|
||||
swap->weight = detached->weight;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Balance the critical node at the position provided as needed
|
||||
//*************************************************************************
|
||||
void balance_node(Node*& critical_node)
|
||||
{
|
||||
// Step 1: Update weights for all children of the critical node up to the
|
||||
// newly inserted node. This step is costly (in terms of traversing nodes
|
||||
// multiple times during insertion) but doesn't require as much recursion
|
||||
Node* weight_node = critical_node->children[critical_node->dir];
|
||||
while (weight_node)
|
||||
{
|
||||
// Keep going until we reach a terminal node (dir == kNeither)
|
||||
if (kNeither != weight_node->dir)
|
||||
{
|
||||
// Does this insert balance the previous weight factor value?
|
||||
if (weight_node->weight == 1 - weight_node->dir)
|
||||
{
|
||||
weight_node->weight = kNeither;
|
||||
}
|
||||
else
|
||||
{
|
||||
weight_node->weight = weight_node->dir;
|
||||
}
|
||||
|
||||
// Update weight factor node to point to next node
|
||||
weight_node = weight_node->children[weight_node->dir];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop loop, terminal node found
|
||||
break;
|
||||
}
|
||||
} // while(weight_node)
|
||||
|
||||
// Step 2: Update weight for critical_node or rotate tree to balance node
|
||||
if (kNeither == critical_node->weight)
|
||||
{
|
||||
critical_node->weight = critical_node->dir;
|
||||
}
|
||||
// If direction is different than weight, then it will now be balanced
|
||||
else if (critical_node->dir != critical_node->weight)
|
||||
{
|
||||
critical_node->weight = kNeither;
|
||||
}
|
||||
// Rotate is required to balance the tree at the critical node
|
||||
else
|
||||
{
|
||||
// If critical node matches child node direction then perform a two
|
||||
// node rotate in the direction of the critical node
|
||||
if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
|
||||
{
|
||||
rotate_2node(critical_node, critical_node->dir);
|
||||
}
|
||||
// Otherwise perform a three node rotation in the direction of the
|
||||
// critical node
|
||||
else
|
||||
{
|
||||
rotate_3node(critical_node, critical_node->dir,
|
||||
critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the node whose key would go before all the other keys from the
|
||||
/// position provided
|
||||
//*************************************************************************
|
||||
Node* find_limit_node(Node* position, const int8_t dir) const
|
||||
{
|
||||
// Something at this position and in the direction specified? keep going
|
||||
Node* limit_node = position;
|
||||
while (limit_node && limit_node->children[dir])
|
||||
{
|
||||
limit_node = limit_node->children[dir];
|
||||
}
|
||||
|
||||
// Return the limit node position found
|
||||
return limit_node;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Find the node whose key would go before all the other keys from the
|
||||
/// position provided
|
||||
//*************************************************************************
|
||||
const Node* find_limit_node(const Node* position, const int8_t dir) const
|
||||
{
|
||||
// Something at this position and in the direction specified? keep going
|
||||
const Node* limit_node = position;
|
||||
while (limit_node && limit_node->children[dir])
|
||||
{
|
||||
limit_node = limit_node->children[dir];
|
||||
}
|
||||
|
||||
// Return the limit node position found
|
||||
return limit_node;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Rotate two nodes at the position provided the to balance the tree
|
||||
//*************************************************************************
|
||||
void rotate_2node(Node*& position, uint8_t dir)
|
||||
{
|
||||
// A C A B
|
||||
// B C -> A E OR B C -> D A
|
||||
// D E B D D E E C
|
||||
// C (new position) becomes the root
|
||||
// A (position) takes ownership of D as its children[kRight] child
|
||||
// C (new position) takes ownership of A as its left child
|
||||
// OR
|
||||
// B (new position) becomes the root
|
||||
// A (position) takes ownership of E as its left child
|
||||
// B (new position) takes ownership of A as its right child
|
||||
|
||||
// Capture new root
|
||||
Node* new_root = position->children[dir];
|
||||
// Replace position's previous child with new root's other child
|
||||
position->children[dir] = new_root->children[1 - dir];
|
||||
// New root now becomes parent of current position
|
||||
new_root->children[1 - dir] = position;
|
||||
// Clear weight factor from current position
|
||||
position->weight = kNeither;
|
||||
// Newly detached right now becomes current position
|
||||
position = new_root;
|
||||
// Clear weight factor from new root
|
||||
position->weight = kNeither;
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
/// Rotate three nodes at the position provided the to balance the tree
|
||||
//*************************************************************************
|
||||
void rotate_3node(Node*& position, uint8_t dir, uint8_t third)
|
||||
{
|
||||
// __A__ __E__ __A__ __D__
|
||||
// _B_ C -> B A OR B _C_ -> A C
|
||||
// D E D F G C D E B F G E
|
||||
// F G F G
|
||||
// E (new position) becomes the root
|
||||
// B (position) takes ownership of F as its left child
|
||||
// A takes ownership of G as its right child
|
||||
// OR
|
||||
// D (new position) becomes the root
|
||||
// A (position) takes ownership of F as its right child
|
||||
// C takes ownership of G as its left child
|
||||
|
||||
// Capture new root (either E or D depending on dir)
|
||||
Node* new_root = position->children[dir]->children[1 - dir];
|
||||
// Set weight factor for B or C based on F or G existing and being a different than dir
|
||||
position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
|
||||
|
||||
// Detach new root from its tree (replace with new roots child)
|
||||
position->children[dir]->children[1 - dir] =
|
||||
new_root->children[dir];
|
||||
// Attach current left tree to new root
|
||||
new_root->children[dir] = position->children[dir];
|
||||
// Set weight factor for A based on F or G
|
||||
position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
|
||||
|
||||
// Move new root's right tree to current roots left tree
|
||||
position->children[dir] = new_root->children[1 - dir];
|
||||
// Attach current root to new roots right tree
|
||||
new_root->children[1 - dir] = position;
|
||||
// Replace current position with new root
|
||||
position = new_root;
|
||||
// Clear weight factor for new current position
|
||||
position->weight = kNeither;
|
||||
}
|
||||
|
||||
|
||||
size_type current_size; ///< The number of the used nodes.
|
||||
const size_type MAX_SIZE; ///< The maximum size of the set.
|
||||
Node* root_node; ///< The node that acts as the set root.
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -396,7 +396,7 @@ namespace
|
||||
{
|
||||
Data data(initial_data.begin(), initial_data.end());
|
||||
|
||||
CHECK_THROW(data.insert(std::make_pair(std::string("10"), 10)), etl::map_full);
|
||||
CHECK_THROW(data.insert(std::make_pair(std::string("10"), 10)), etl::multimap_full);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -436,7 +436,7 @@ namespace
|
||||
{
|
||||
Data data;
|
||||
|
||||
CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::map_full);
|
||||
CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::multimap_full);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
|
||||
@ -371,7 +371,7 @@ namespace
|
||||
{
|
||||
Data data(initial_data.begin(), initial_data.end());
|
||||
|
||||
CHECK_THROW(data.insert(10), etl::set_full);
|
||||
CHECK_THROW(data.insert(10), etl::multiset_full);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
@ -411,7 +411,7 @@ namespace
|
||||
{
|
||||
Data data;
|
||||
|
||||
CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::set_full);
|
||||
CHECK_THROW(data.insert(excess_data.begin(), excess_data.end()), etl::multiset_full);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
|
||||
@ -198,6 +198,7 @@
|
||||
<ClInclude Include="..\..\multimap.h" />
|
||||
<ClInclude Include="..\..\multimap_base.h" />
|
||||
<ClInclude Include="..\..\multiset.h" />
|
||||
<ClInclude Include="..\..\multiset_base.h" />
|
||||
<ClInclude Include="..\..\murmur3.h" />
|
||||
<ClInclude Include="..\..\nullptr.h" />
|
||||
<ClInclude Include="..\..\numeric.h" />
|
||||
|
||||
@ -462,6 +462,9 @@
|
||||
<ClInclude Include="..\..\multimap_base.h">
|
||||
<Filter>ETL\Containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\multiset_base.h">
|
||||
<Filter>ETL\Containers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\unittest-cpp\UnitTest++\AssertException.cpp">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user