Created multiset_base.h and derived imultiset from it.

Moved non-type code to base classes.
This commit is contained in:
John Wellbelove 2015-12-05 15:56:57 +00:00
parent 5794aebd8b
commit b3b9426a69
10 changed files with 274 additions and 678 deletions

View File

@ -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
}

View File

@ -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
View File

@ -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;
}
};
}

View File

@ -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__

View File

@ -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")
{
}
};

View File

@ -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.
};
}

View File

@ -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);
}
//*************************************************************************

View File

@ -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);
}
//*************************************************************************

View File

@ -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" />

View File

@ -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">