diff --git a/imultimap.h b/imultimap.h index 67b23b89..63ba491f 100644 --- a/imultimap.h +++ b/imultimap.h @@ -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 } diff --git a/imultiset.h b/imultiset.h index d843f508..d35b62dd 100644 --- a/imultiset.h +++ b/imultiset.h @@ -37,7 +37,7 @@ SOFTWARE. #include #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 - 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* 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& 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; - } - }; } diff --git a/iset.h b/iset.h index 6e584b34..03ab618f 100644 --- a/iset.h +++ b/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* 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& 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; - } }; } diff --git a/map_base.h b/map_base.h index ab5c61c8..12264f9d 100644 --- a/map_base.h +++ b/map_base.h @@ -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__ diff --git a/multimap_base.h b/multimap_base.h index 6fcc8c9c..b9201f32 100644 --- a/multimap_base.h +++ b/multimap_base.h @@ -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") { } }; diff --git a/set_base.h b/set_base.h index f33d3fe6..1148bfac 100644 --- a/set_base.h +++ b/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. }; } diff --git a/test/test_multimap.cpp b/test/test_multimap.cpp index 5194384e..180ce8d0 100644 --- a/test/test_multimap.cpp +++ b/test/test_multimap.cpp @@ -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); } //************************************************************************* diff --git a/test/test_multiset.cpp b/test/test_multiset.cpp index 04d2638a..7ba863ef 100644 --- a/test/test_multiset.cpp +++ b/test/test_multiset.cpp @@ -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); } //************************************************************************* diff --git a/test/vs2015/etl.vcxproj b/test/vs2015/etl.vcxproj index cdb2d35c..79f31dcb 100644 --- a/test/vs2015/etl.vcxproj +++ b/test/vs2015/etl.vcxproj @@ -198,6 +198,7 @@ + diff --git a/test/vs2015/etl.vcxproj.filters b/test/vs2015/etl.vcxproj.filters index 2702ee64..848a444d 100644 --- a/test/vs2015/etl.vcxproj.filters +++ b/test/vs2015/etl.vcxproj.filters @@ -462,6 +462,9 @@ ETL\Containers + + ETL\Containers +