Stefan Scholz / ETL
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers multimap.h Source File

multimap.h

Go to the documentation of this file.
00001 ///\file
00002 
00003 /******************************************************************************
00004 The MIT License(MIT)
00005 
00006 Embedded Template Library.
00007 https://github.com/ETLCPP/etl
00008 http://www.etlcpp.com
00009 
00010 Copyright(c) 2014 jwellbelove, rlindeman
00011 
00012 Permission is hereby granted, free of charge, to any person obtaining a copy
00013 of this software and associated documentation files(the "Software"), to deal
00014 in the Software without restriction, including without limitation the rights
00015 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
00016 copies of the Software, and to permit persons to whom the Software is
00017 furnished to do so, subject to the following conditions :
00018 
00019 The above copyright notice and this permission notice shall be included in all
00020 copies or substantial portions of the Software.
00021 
00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00023 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00024 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
00025 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00026 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00027 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00028 SOFTWARE.
00029 ******************************************************************************/
00030 
00031 #ifndef __ETL_MULTIMAP__
00032 #define __ETL_MULTIMAP__
00033 
00034 #include <stddef.h>
00035 #include <iterator>
00036 #include <algorithm>
00037 #include <functional>
00038 
00039 #include "platform.h "
00040 #include "container.h "
00041 #include "pool.h "
00042 #include "exception.h "
00043 #include "error_handler.h "
00044 #include "debug_count.h "
00045 #include "nullptr.h "
00046 #include "type_traits.h "
00047 #include "parameter_type.h "
00048 
00049 #ifdef ETL_COMPILER_MICROSOFT
00050 #undef min
00051 #endif
00052 
00053 #undef ETL_FILE
00054 #define ETL_FILE "9"
00055 
00056 //*****************************************************************************
00057 /// A multimap with the capacity defined at compile time.
00058 ///\ingroup containers
00059 //*****************************************************************************
00060 
00061 namespace etl
00062 {
00063   //***************************************************************************
00064   /// Exception for the map.
00065   ///\ingroup map
00066   //***************************************************************************
00067   class multimap_exception : public etl::exception
00068   {
00069   public:
00070 
00071     multimap_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
00072       : exception(reason_, file_name_, line_number_)
00073     {
00074     }
00075   };
00076 
00077   //***************************************************************************
00078   /// Full exception for the map.
00079   ///\ingroup map
00080   //***************************************************************************
00081   class multimap_full : public etl::multimap_exception
00082   {
00083   public:
00084 
00085     multimap_full(string_type file_name_, numeric_type line_number_)
00086       : etl::multimap_exception("multimap:full", file_name_, line_number_)
00087     {
00088     }
00089   };
00090 
00091   //***************************************************************************
00092   /// Map out of bounds exception.
00093   ///\ingroup map
00094   //***************************************************************************
00095   class multimap_out_of_bounds : public etl::multimap_exception
00096   {
00097   public:
00098 
00099     multimap_out_of_bounds(string_type file_name_, numeric_type line_number_)
00100       : etl::multimap_exception("multimap:bounds", file_name_, line_number_)
00101     {
00102     }
00103   };
00104 
00105   //***************************************************************************
00106   /// Iterator exception for the map.
00107   ///\ingroup map
00108   //***************************************************************************
00109   class multimap_iterator : public etl::multimap_exception
00110   {
00111   public:
00112 
00113     multimap_iterator(string_type file_name_, numeric_type line_number_)
00114       : etl::multimap_exception("multimap:iterator", file_name_, line_number_)
00115     {
00116     }
00117   };
00118 
00119   //***************************************************************************
00120   /// The base class for all maps.
00121   ///\ingroup map
00122   //***************************************************************************
00123   class multimap_base
00124   {
00125   public:
00126 
00127     typedef size_t size_type; ///< The type used for determining the size of map.
00128 
00129     //*************************************************************************
00130     /// Gets the size of the map.
00131     //*************************************************************************
00132     size_type size() const
00133     {
00134       return current_size;
00135     }
00136 
00137     //*************************************************************************
00138     /// Gets the maximum possible size of the map.
00139     //*************************************************************************
00140     size_type max_size() const
00141     {
00142       return CAPACITY;
00143     }
00144 
00145     //*************************************************************************
00146     /// Checks to see if the map is empty.
00147     //*************************************************************************
00148     bool empty() const
00149     {
00150       return current_size == 0;
00151     }
00152 
00153     //*************************************************************************
00154     /// Checks to see if the map is full.
00155     //*************************************************************************
00156     bool full() const
00157     {
00158       return current_size == CAPACITY;
00159     }
00160 
00161     //*************************************************************************
00162     /// Returns the capacity of the vector.
00163     ///\return The capacity of the vector.
00164     //*************************************************************************
00165     size_type capacity() const
00166     {
00167       return CAPACITY;
00168     }
00169 
00170     //*************************************************************************
00171     /// Returns the remaining capacity.
00172     ///\return The remaining capacity.
00173     //*************************************************************************
00174     size_t available() const
00175     {
00176       return max_size() - size();
00177     }
00178 
00179   protected:
00180 
00181     enum
00182     {
00183       kLeft,
00184       kRight,
00185       kNeither
00186     };
00187 
00188     //*************************************************************************
00189     /// The node element in the multimap.
00190     //*************************************************************************
00191     struct Node
00192     {
00193       //***********************************************************************
00194       /// Constructor
00195       //***********************************************************************
00196       Node() :
00197         weight(kNeither),
00198         dir(kNeither)
00199       {
00200       }
00201 
00202       //***********************************************************************
00203       /// Marks the node as a leaf.
00204       //***********************************************************************
00205       void mark_as_leaf()
00206       {
00207         weight = kNeither;
00208         dir = kNeither;
00209         parent = std::nullptr;
00210         children[0] = std::nullptr;
00211         children[1] = std::nullptr;
00212       }
00213 
00214       Node* parent;
00215       Node* children[2];
00216       uint_least8_t weight;
00217       uint_least8_t dir;
00218     };
00219 
00220     //*************************************************************************
00221     /// The constructor that is called from derived classes.
00222     //*************************************************************************
00223     multimap_base(size_type max_size_)
00224       : current_size(0)
00225       , CAPACITY(max_size_)
00226       , root_node(std::nullptr)
00227 
00228     {
00229     }
00230 
00231     //*************************************************************************
00232     /// Balance the critical node at the position provided as needed
00233     //*************************************************************************
00234     void balance_node(Node*& critical_node)
00235     {
00236       // Step 1: Update weights for all children of the critical node up to the
00237       // newly inserted node. This step is costly (in terms of traversing nodes
00238       // multiple times during insertion) but doesn't require as much recursion
00239       Node* weight_node = critical_node->children[critical_node->dir];
00240       while (weight_node)
00241       {
00242         // Keep going until we reach a terminal node (dir == kNeither)
00243         if (kNeither != weight_node->dir)
00244         {
00245           // Does this insert balance the previous weight factor value?
00246           if (weight_node->weight == 1 - weight_node->dir)
00247           {
00248             weight_node->weight = kNeither;
00249           }
00250           else
00251           {
00252             weight_node->weight = weight_node->dir;
00253           }
00254 
00255           // Update weight factor node to point to next node
00256           weight_node = weight_node->children[weight_node->dir];
00257         }
00258         else
00259         {
00260           // Stop loop, terminal node found
00261           break;
00262         }
00263       } // while(weight_node)
00264 
00265         // Step 2: Update weight for critical_node or rotate tree to balance node
00266       if (kNeither == critical_node->weight)
00267       {
00268         critical_node->weight = critical_node->dir;
00269       }
00270       // If direction is different than weight, then it will now be balanced
00271       else if (critical_node->dir != critical_node->weight)
00272       {
00273         critical_node->weight = kNeither;
00274       }
00275       // Rotate is required to balance the tree at the critical node
00276       else
00277       {
00278         // If critical node matches child node direction then perform a two
00279         // node rotate in the direction of the critical node
00280         if (critical_node->weight == critical_node->children[critical_node->dir]->dir)
00281         {
00282           rotate_2node(critical_node, critical_node->dir);
00283         }
00284         // Otherwise perform a three node rotation in the direction of the
00285         // critical node
00286         else
00287         {
00288           rotate_3node(critical_node, critical_node->dir,
00289             critical_node->children[critical_node->dir]->children[1 - critical_node->dir]->dir);
00290         }
00291       }
00292     }
00293 
00294     //*************************************************************************
00295     /// Rotate two nodes at the position provided the to balance the tree
00296     //*************************************************************************
00297     void rotate_2node(Node*& position, uint_least8_t dir)
00298     {
00299       //     A            C             A          B
00300       //   B   C   ->   A   E   OR    B   C  ->  D   A
00301       //      D E      B D           D E            E C
00302       // C (new position) becomes the root
00303       // A (position) takes ownership of D as its children[kRight] child
00304       // C (new position) takes ownership of A as its left child
00305       //                 OR
00306       // B (new position) becomes the root
00307       // A (position) takes ownership of E as its left child
00308       // B (new position) takes ownership of A as its right child
00309 
00310       // Capture new root (either B or C depending on dir) and its parent
00311       Node* new_root = position->children[dir];
00312 
00313       // Replace position's previous child with new root's other child
00314       position->children[dir] = new_root->children[1 - dir];
00315       // Update new root's other child parent pointer
00316       if (position->children[dir])
00317       {
00318         position->children[dir]->parent = position;
00319       }
00320 
00321       // New root's parent becomes current position's parent
00322       new_root->parent = position->parent;
00323       new_root->children[1 - dir] = position;
00324       new_root->dir = 1 - dir;
00325 
00326       // Clear weight factor from current position
00327       position->weight = kNeither;
00328       // Position's parent becomes new_root
00329       position->parent = new_root;
00330       position = new_root;
00331       // Clear weight factor from new root
00332       position->weight = kNeither;
00333     }
00334 
00335     //*************************************************************************
00336     /// Rotate three nodes at the position provided the to balance the tree
00337     //*************************************************************************
00338     void rotate_3node(Node*& position, uint_least8_t dir, uint_least8_t third)
00339     {
00340       //        __A__             __E__            __A__             __D__
00341       //      _B_    C    ->     B     A    OR    B    _C_   ->     A     C
00342       //     D   E              D F   G C             D   E        B F   G E
00343       //        F G                                  F G
00344       // E (new position) becomes the root
00345       // B (position) takes ownership of F as its left child
00346       // A takes ownership of G as its right child
00347       //                  OR
00348       // D (new position) becomes the root
00349       // A (position) takes ownership of F as its right child
00350       // C takes ownership of G as its left child
00351 
00352       // Capture new root (either E or D depending on dir)
00353       Node* new_root = position->children[dir]->children[1 - dir];
00354       // Set weight factor for B or C based on F or G existing and being a different than dir
00355       position->children[dir]->weight = third != kNeither && third != dir ? dir : kNeither;
00356 
00357       // Detach new root from its tree (replace with new roots child)
00358       position->children[dir]->children[1 - dir] = new_root->children[dir];
00359       // Update new roots child parent pointer
00360       if (new_root->children[dir])
00361       {
00362         new_root->children[dir]->parent = position->children[dir];
00363       }
00364 
00365       // Attach current left tree to new root and update its parent
00366       new_root->children[dir] = position->children[dir];
00367       position->children[dir]->parent = new_root;
00368 
00369       // Set weight factor for A based on F or G
00370       position->weight = third != kNeither && third == dir ? 1 - dir : kNeither;
00371 
00372       // Move new root's right tree to current roots left tree
00373       position->children[dir] = new_root->children[1 - dir];
00374       if (new_root->children[1 - dir])
00375       {
00376         new_root->children[1 - dir]->parent = position;
00377       }
00378 
00379       // Attach current root to new roots right tree and assume its parent
00380       new_root->parent = position->parent;
00381       new_root->children[1 - dir] = position;
00382       new_root->dir = 1 - dir;
00383 
00384       // Update current position's parent and replace with new root
00385       position->parent = new_root;
00386       position = new_root;
00387       // Clear weight factor for new current position
00388       position->weight = kNeither;
00389     }
00390 
00391     //*************************************************************************
00392     /// Find the next node in sequence from the node provided
00393     //*************************************************************************
00394     void next_node(Node*& position) const
00395     {
00396       if (position)
00397       {
00398         // Is there a tree on the right? then find the minimum of that tree
00399         if (position->children[kRight])
00400         {
00401           // Return minimum node found
00402           position = find_limit_node(position->children[kRight], kLeft);
00403         }
00404         // Otherwise find the parent of this node
00405         else
00406         {
00407           // Start with current position as parent
00408           Node* parent = position;
00409           do {
00410             // Update current position as previous parent
00411             position = parent;
00412             // Find parent of current position
00413             parent = position->parent; // find_parent_node(root_node, position);
00414                                        // Repeat while previous position was on right side of parent tree
00415           } while (parent && parent->children[kRight] == position);
00416 
00417           // Set parent node as the next position
00418           position = parent;
00419         }
00420       }
00421     }
00422 
00423     //*************************************************************************
00424     /// Find the next node in sequence from the node provided
00425     //*************************************************************************
00426     void next_node(const Node*& position) const
00427     {
00428       if (position)
00429       {
00430         // Is there a tree on the right? then find the minimum of that tree
00431         if (position->children[kRight])
00432         {
00433           // Return minimum node found
00434           position = find_limit_node(position->children[kRight], kLeft);
00435         }
00436         // Otherwise find the parent of this node
00437         else
00438         {
00439           // Start with current position as parent
00440           const Node* parent = position;
00441           do {
00442             // Update current position as previous parent
00443             position = parent;
00444             // Find parent of current position
00445             parent = position->parent;
00446             // Repeat while previous position was on right side of parent tree
00447           } while (parent && parent->children[kRight] == position);
00448 
00449           // Set parent node as the next position
00450           position = parent;
00451         }
00452       }
00453     }
00454 
00455     //*************************************************************************
00456     /// Find the previous node in sequence from the node provided
00457     //*************************************************************************
00458     void prev_node(Node*& position) const
00459     {
00460       // If starting at the terminal end, the previous node is the maximum node
00461       // from the root
00462       if (!position)
00463       {
00464         position = find_limit_node(root_node, kRight);
00465       }
00466       else
00467       {
00468         // Is there a tree on the left? then find the maximum of that tree
00469         if (position->children[kLeft])
00470         {
00471           // Return maximum node found
00472           position = find_limit_node(position->children[kLeft], kRight);
00473         }
00474         // Otherwise find the parent of this node
00475         else
00476         {
00477           // Start with current position as parent
00478           Node* parent = position;
00479           do {
00480             // Update current position as previous parent
00481             position = parent;
00482             // Find parent of current position
00483             parent = position->parent;
00484             // Repeat while previous position was on left side of parent tree
00485           } while (parent && parent->children[kLeft] == position);
00486 
00487           // Set parent node as the next position
00488           position = parent;
00489         }
00490       }
00491     }
00492 
00493     //*************************************************************************
00494     /// Find the previous node in sequence from the node provided
00495     //*************************************************************************
00496     void prev_node(const Node*& position) const
00497     {
00498       // If starting at the terminal end, the previous node is the maximum node
00499       // from the root
00500       if (!position)
00501       {
00502         position = find_limit_node(root_node, kRight);
00503       }
00504       else
00505       {
00506         // Is there a tree on the left? then find the maximum of that tree
00507         if (position->children[kLeft])
00508         {
00509           // Return maximum node found
00510           position = find_limit_node(position->children[kLeft], kRight);
00511         }
00512         // Otherwise find the parent of this node
00513         else
00514         {
00515           // Start with current position as parent
00516           const Node* parent = position;
00517           do {
00518             // Update current position as previous parent
00519             position = parent;
00520             // Find parent of current position
00521             parent = position->parent;
00522             // Repeat while previous position was on left side of parent tree
00523           } while (parent && parent->children[kLeft] == position);
00524 
00525           // Set parent node as the next position
00526           position = parent;
00527         }
00528       }
00529     }
00530 
00531     //*************************************************************************
00532     /// Find the node whose key would go before all the other keys from the
00533     /// position provided
00534     //*************************************************************************
00535     Node* find_limit_node(Node* position, const int8_t dir) const
00536     {
00537       // Something at this position and in the direction specified? keep going
00538       Node* limit_node = position;
00539       while (limit_node && limit_node->children[dir])
00540       {
00541         limit_node = limit_node->children[dir];
00542       }
00543 
00544       // Return the limit node position found
00545       return limit_node;
00546     }
00547 
00548     //*************************************************************************
00549     /// Attach the provided node to the position provided
00550     //*************************************************************************
00551     void attach_node(Node* parent, Node*& position, Node& node)
00552     {
00553       // Mark new node as leaf on attach to tree at position provided
00554       node.mark_as_leaf();
00555 
00556       // Keep track of this node's parent
00557       node.parent = parent;
00558 
00559       // Add the node here
00560       position = &node;
00561 
00562       // One more.
00563       ++current_size;
00564     }
00565 
00566     //*************************************************************************
00567     /// Detach the node at the position provided
00568     //*************************************************************************
00569     void detach_node(Node*& position, Node*& replacement)
00570     {
00571       // Make temporary copy of actual nodes involved because we might lose
00572       // their references in the process (e.g. position is the same as
00573       // replacement or replacement is a child of position)
00574       Node* detached = position;
00575       Node* swap = replacement;
00576 
00577       // Update current position to point to swap (replacement) node first
00578       position = swap;
00579 
00580       // Update replacement node to point to child in opposite direction
00581       // otherwise we might lose the other child of the swap node
00582       replacement = swap->children[1 - swap->dir];
00583 
00584       // Point swap node to detached node's parent, children and weight
00585       swap->parent = detached->parent;
00586       swap->children[kLeft] = detached->children[kLeft];
00587       swap->children[kRight] = detached->children[kRight];
00588       if (swap->children[kLeft])
00589       {
00590         swap->children[kLeft]->parent = swap;
00591       }
00592       if (swap->children[kRight])
00593       {
00594         swap->children[kRight]->parent = swap;
00595       }
00596       swap->weight = detached->weight;
00597     }
00598 
00599     size_type current_size;   ///< The number of the used nodes.
00600     const size_type CAPACITY; ///< The maximum size of the map.
00601     Node* root_node;          ///< The node that acts as the multimap root.
00602     etl::debug_count construct_count;
00603   };
00604 
00605   //***************************************************************************
00606   /// A templated base for all etl::multimap types.
00607   ///\ingroup map
00608   //***************************************************************************
00609   template <typename TKey, typename TMapped, typename TKeyCompare>
00610   class imultimap : public etl::multimap_base
00611   {
00612   public:
00613 
00614     typedef std::pair<const TKey, TMapped> value_type;
00615     typedef const TKey                     key_type;
00616     typedef TMapped                        mapped_type;
00617     typedef TKeyCompare                    key_compare;
00618     typedef value_type&                    reference;
00619     typedef const value_type&              const_reference;
00620     typedef value_type*                    pointer;
00621     typedef const value_type*              const_pointer;
00622     typedef size_t                         size_type;
00623 
00624     //*************************************************************************
00625     /// How to compare two key elements.
00626     //*************************************************************************
00627     struct key_comp
00628     {
00629       bool operator ()(const key_type& key1, const key_type& key2) const
00630       {
00631         return key_compare()(key1, key2);
00632       }
00633     };
00634 
00635     //*************************************************************************
00636     /// How to compare two value elements.
00637     //*************************************************************************
00638     struct value_comp
00639     {
00640       bool operator ()(const value_type& value1, const value_type& value2) const
00641       {
00642         return key_compare()(value1.first, value2.first);
00643       }
00644     };
00645 
00646   protected:
00647 
00648     //*************************************************************************
00649     /// The data node element in the multimap.
00650     //*************************************************************************
00651     struct Data_Node : public Node
00652     {
00653       explicit Data_Node(value_type value_)
00654         : value(value_)
00655       {
00656       }
00657 
00658       value_type value;
00659     };
00660 
00661     /// Defines the key value parameter type
00662     typedef typename etl::parameter_type<TKey>::type key_parameter_t;
00663 
00664     //*************************************************************************
00665     /// How to compare node elements.
00666     //*************************************************************************
00667     bool node_comp(const Data_Node& node1, const Data_Node& node2) const
00668     {
00669       return key_compare()(node1.value.first, node2.value.first);
00670     }
00671 
00672     bool node_comp(const Data_Node& node, key_parameter_t key) const
00673     {
00674       return key_compare()(node.value.first, key);
00675     }
00676 
00677     bool node_comp(key_parameter_t key, const Data_Node& node) const
00678     {
00679       return key_compare()(key, node.value.first);
00680     }
00681 
00682   private:
00683 
00684     /// The pool of data nodes used in the multimap.
00685     ipool* p_node_pool;
00686 
00687     //*************************************************************************
00688     /// Downcast a Node* to a Data_Node*
00689     //*************************************************************************
00690     static Data_Node* data_cast(Node* p_node)
00691     {
00692       return static_cast<Data_Node*>(p_node);
00693     }
00694 
00695     //*************************************************************************
00696     /// Downcast a Node& to a Data_Node&
00697     //*************************************************************************
00698     static Data_Node& data_cast(Node& node)
00699     {
00700       return static_cast<Data_Node&>(node);
00701     }
00702 
00703     //*************************************************************************
00704     /// Downcast a const Node* to a const Data_Node*
00705     //*************************************************************************
00706     static const Data_Node* data_cast(const Node* p_node)
00707     {
00708       return static_cast<const Data_Node*>(p_node);
00709     }
00710 
00711     //*************************************************************************
00712     /// Downcast a const Node& to a const Data_Node&
00713     //*************************************************************************
00714     static const Data_Node& data_cast(const Node& node)
00715     {
00716       return static_cast<const Data_Node&>(node);
00717     }
00718 
00719   public:
00720     //*************************************************************************
00721     /// iterator.
00722     //*************************************************************************
00723     class iterator : public std::iterator<std::bidirectional_iterator_tag, value_type>
00724     {
00725     public:
00726 
00727       friend class imultimap;
00728 
00729       iterator()
00730         : p_multimap(std::nullptr)
00731         , p_node(std::nullptr)
00732       {
00733       }
00734 
00735       iterator(imultimap& multimap)
00736         : p_multimap(&multimap)
00737         , p_node(std::nullptr)
00738       {
00739       }
00740 
00741       iterator(imultimap& multimap, Node* node)
00742         : p_multimap(&multimap)
00743         , p_node(node)
00744       {
00745       }
00746 
00747       iterator(const iterator& other)
00748         : p_multimap(other.p_multimap)
00749         , p_node(other.p_node)
00750       {
00751       }
00752 
00753       ~iterator()
00754       {
00755       }
00756 
00757       iterator& operator ++()
00758       {
00759         p_multimap->next_node(p_node);
00760         return *this;
00761       }
00762 
00763       iterator operator ++(int)
00764       {
00765         iterator temp(*this);
00766         p_multimap->next_node(p_node);
00767         return temp;
00768       }
00769 
00770       iterator& operator --()
00771       {
00772         p_multimap->prev_node(p_node);
00773         return *this;
00774       }
00775 
00776       iterator operator --(int)
00777       {
00778         iterator temp(*this);
00779         p_multimap->prev_node(p_node);
00780         return temp;
00781       }
00782 
00783       iterator operator =(const iterator& other)
00784       {
00785         p_multimap = other.p_multimap;
00786         p_node = other.p_node;
00787         return *this;
00788       }
00789 
00790       reference operator *()
00791       {
00792         return imultimap::data_cast(p_node)->value;
00793       }
00794 
00795       const_reference operator *() const
00796       {
00797         return imultimap::data_cast(p_node)->value;
00798       }
00799 
00800       pointer operator &()
00801       {
00802         return &(imultimap::data_cast(p_node)->value);
00803       }
00804 
00805       const_pointer operator &() const
00806       {
00807         return &(imultimap::data_cast(p_node)->value);
00808       }
00809 
00810       pointer operator ->()
00811       {
00812         return &(imultimap::data_cast(p_node)->value);
00813       }
00814 
00815       const_pointer operator ->() const
00816       {
00817         return &(imultimap::data_cast(p_node)->value);
00818       }
00819 
00820       friend bool operator == (const iterator& lhs, const iterator& rhs)
00821       {
00822         return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
00823       }
00824 
00825       friend bool operator != (const iterator& lhs, const iterator& rhs)
00826       {
00827         return !(lhs == rhs);
00828       }
00829 
00830     private:
00831 
00832       // Pointer to multimap associated with this iterator
00833       imultimap* p_multimap;
00834 
00835       // Pointer to the current node for this iterator
00836       Node* p_node;
00837     };
00838     friend class iterator;
00839 
00840     //*************************************************************************
00841     /// const_iterator
00842     //*************************************************************************
00843     class const_iterator : public std::iterator<std::bidirectional_iterator_tag, const value_type>
00844     {
00845     public:
00846 
00847       friend class imultimap;
00848 
00849       const_iterator()
00850         : p_multimap(std::nullptr)
00851         , p_node(std::nullptr)
00852       {
00853       }
00854 
00855       const_iterator(const imultimap& multimap)
00856         : p_multimap(&multimap)
00857         , p_node(std::nullptr)
00858       {
00859       }
00860 
00861       const_iterator(const imultimap& multimap, const Node* node)
00862         : p_multimap(&multimap)
00863         , p_node(node)
00864       {
00865       }
00866 
00867       const_iterator(const typename imultimap::iterator& other)
00868         : p_multimap(other.p_multimap)
00869         , p_node(other.p_node)
00870       {
00871       }
00872 
00873       const_iterator(const const_iterator& other)
00874         : p_multimap(other.p_multimap)
00875         , p_node(other.p_node)
00876       {
00877       }
00878 
00879       ~const_iterator()
00880       {
00881       }
00882 
00883       const_iterator& operator ++()
00884       {
00885         p_multimap->next_node(p_node);
00886         return *this;
00887       }
00888 
00889       const_iterator operator ++(int)
00890       {
00891         const_iterator temp(*this);
00892         p_multimap->next_node(p_node);
00893         return temp;
00894       }
00895 
00896       const_iterator& operator --()
00897       {
00898         p_multimap->prev_node(p_node);
00899         return *this;
00900       }
00901 
00902       const_iterator operator --(int)
00903       {
00904         const_iterator temp(*this);
00905         p_multimap->prev_node(p_node);
00906         return temp;
00907       }
00908 
00909       const_iterator operator =(const const_iterator& other)
00910       {
00911         p_multimap = other.p_multimap;
00912         p_node = other.p_node;
00913         return *this;
00914       }
00915 
00916       const_reference operator *() const
00917       {
00918         return imultimap::data_cast(p_node)->value;
00919       }
00920 
00921       const_pointer operator &() const
00922       {
00923         return imultimap::data_cast(p_node)->value;
00924       }
00925 
00926       const_pointer operator ->() const
00927       {
00928         return &(imultimap::data_cast(p_node)->value);
00929       }
00930 
00931       friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
00932       {
00933         return lhs.p_multimap == rhs.p_multimap && lhs.p_node == rhs.p_node;
00934       }
00935 
00936       friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
00937       {
00938         return !(lhs == rhs);
00939       }
00940 
00941     private:
00942       // Pointer to multimap associated with this iterator
00943       const imultimap* p_multimap;
00944 
00945       // Pointer to the current node for this iterator
00946       const Node* p_node;
00947     };
00948     friend class const_iterator;
00949 
00950     typedef typename std::iterator_traits<iterator>::difference_type difference_type;
00951 
00952     typedef std::reverse_iterator<iterator>       reverse_iterator;
00953     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00954 
00955 
00956     //*************************************************************************
00957     /// Gets the beginning of the multimap.
00958     //*************************************************************************
00959     iterator begin()
00960     {
00961       return iterator(*this, find_limit_node(root_node, kLeft));
00962     }
00963 
00964     //*************************************************************************
00965     /// Gets the beginning of the multimap.
00966     //*************************************************************************
00967     const_iterator begin() const
00968     {
00969       return const_iterator(*this, find_limit_node(root_node, kLeft));
00970     }
00971 
00972     //*************************************************************************
00973     /// Gets the end of the multimap.
00974     //*************************************************************************
00975     iterator end()
00976     {
00977       return iterator(*this);
00978     }
00979 
00980     //*************************************************************************
00981     /// Gets the end of the multimap.
00982     //*************************************************************************
00983     const_iterator end() const
00984     {
00985       return const_iterator(*this);
00986     }
00987 
00988     //*************************************************************************
00989     /// Gets the beginning of the multimap.
00990     //*************************************************************************
00991     const_iterator cbegin() const
00992     {
00993       return const_iterator(*this, find_limit_node(root_node, kLeft));
00994     }
00995 
00996     //*************************************************************************
00997     /// Gets the end of the multimap.
00998     //*************************************************************************
00999     const_iterator cend() const
01000     {
01001       return const_iterator(*this);
01002     }
01003 
01004     //*************************************************************************
01005     /// Gets the reverse beginning of the list.
01006     //*************************************************************************
01007     reverse_iterator rbegin()
01008     {
01009       return reverse_iterator(iterator(*this));
01010     }
01011 
01012     //*************************************************************************
01013     /// Gets the reverse beginning of the list.
01014     //*************************************************************************
01015     const_reverse_iterator rbegin() const
01016     {
01017       return const_reverse_iterator(const_iterator(*this));
01018     }
01019 
01020     //*************************************************************************
01021     /// Gets the reverse end of the list.
01022     //*************************************************************************
01023     reverse_iterator rend()
01024     {
01025       return reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
01026     }
01027 
01028     //*************************************************************************
01029     /// Gets the reverse end of the list.
01030     //*************************************************************************
01031     const_reverse_iterator rend() const
01032     {
01033       return const_reverse_iterator(iterator(*this, find_limit_node(root_node, kLeft)));
01034     }
01035 
01036     //*************************************************************************
01037     /// Gets the reverse beginning of the list.
01038     //*************************************************************************
01039     const_reverse_iterator crbegin() const
01040     {
01041       return const_reverse_iterator(const_iterator(*this));
01042     }
01043 
01044     //*************************************************************************
01045     /// Gets the reverse end of the list.
01046     //*************************************************************************
01047     const_reverse_iterator crend() const
01048     {
01049       return const_reverse_iterator(const_iterator(*this, find_limit_node(root_node, kLeft)));
01050     }
01051 
01052     //*********************************************************************
01053     /// Assigns values to the multimap.
01054     /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space.
01055     /// If asserts or exceptions are enabled, emits map_iterator if the iterators are reversed.
01056     ///\param first The iterator to the first element.
01057     ///\param last  The iterator to the last element + 1.
01058     //*********************************************************************
01059     template <typename TIterator>
01060     void assign(TIterator first, TIterator last)
01061     {
01062       initialise();
01063       insert(first, last);
01064     }
01065 
01066     //*************************************************************************
01067     /// Clears the multimap.
01068     //*************************************************************************
01069     void clear()
01070     {
01071       initialise();
01072     }
01073 
01074     //*********************************************************************
01075     /// Counts the number of elements that contain the key specified.
01076     ///\param key The key to search for.
01077     ///\return 1 if element was found, 0 otherwise.
01078     //*********************************************************************
01079     size_type count(key_parameter_t key) const
01080     {
01081       return count_nodes(key);
01082     }
01083 
01084     //*************************************************************************
01085     /// Returns two iterators with bounding (lower bound, upper bound) the key
01086     /// provided
01087     //*************************************************************************
01088     std::pair<iterator, iterator> equal_range(key_parameter_t key)
01089     {
01090       return std::make_pair<iterator, iterator>(
01091         iterator(*this, find_lower_node(root_node, key)),
01092         iterator(*this, find_upper_node(root_node, key)));
01093     }
01094 
01095     //*************************************************************************
01096     /// Returns two const iterators with bounding (lower bound, upper bound)
01097     /// the key provided.
01098     //*************************************************************************
01099     std::pair<const_iterator, const_iterator> equal_range(key_parameter_t key) const
01100     {
01101       return std::make_pair<const_iterator, const_iterator>(
01102         const_iterator(*this, find_lower_node(root_node, key)),
01103         const_iterator(*this, find_upper_node(root_node, key)));
01104     }
01105 
01106     //*************************************************************************
01107     /// Erases the value at the specified position.
01108     //*************************************************************************
01109     void erase(iterator position)
01110     {
01111       // Remove the node by its node specified in iterator position
01112       (void)erase(const_iterator(position));
01113     }
01114 
01115     //*************************************************************************
01116     /// Erases the value at the specified position.
01117     //*************************************************************************
01118     iterator erase(const_iterator position)
01119     {
01120       // Cast const away from node to be removed. This is necessary because the
01121       // STL definition of this method requires we provide the next node in the
01122       // sequence as an iterator.
01123       Node* node = const_cast<Node*>(position.p_node);
01124       iterator next(*this, node);
01125       ++next;
01126 
01127       // Remove the non-const node provided
01128       remove_node(node);
01129 
01130       return next;
01131     }
01132 
01133     //*************************************************************************
01134     // Erase the key specified.
01135     //*************************************************************************
01136     size_type erase(key_parameter_t key)
01137     {
01138       // Number of nodes removed
01139       size_type d = 0;
01140       const_iterator lower(*this, find_lower_node(root_node, key));
01141       const_iterator upper(*this, find_upper_node(root_node, key));
01142       while (lower != upper)
01143       {
01144         // Increment count for each node removed
01145         ++d;
01146         // Remove node using the other erase method
01147         (void)erase(lower++);
01148       }
01149 
01150       // Return the total count erased
01151       return d;
01152     }
01153 
01154     //*************************************************************************
01155     /// Erases a range of elements.
01156     //*************************************************************************
01157     iterator erase(iterator first, iterator last)
01158     {
01159       iterator next;
01160       while (first != last)
01161       {
01162         next = erase(const_iterator(first++));
01163       }
01164 
01165       return next;
01166     }
01167 
01168     //*************************************************************************
01169     /// Erases a range of elements.
01170     //*************************************************************************
01171     iterator erase(const_iterator first, const_iterator last)
01172     {
01173       iterator next;
01174       while (first != last)
01175       {
01176         next = erase(first++);
01177       }
01178 
01179       return next;
01180     }
01181 
01182     //*********************************************************************
01183     /// Finds an element.
01184     ///\param key The key to search for.
01185     ///\return An iterator pointing to the element or end() if not found.
01186     //*********************************************************************
01187     iterator find(key_parameter_t key)
01188     {
01189       return iterator(*this, find_node(root_node, key));
01190     }
01191 
01192     //*********************************************************************
01193     /// Finds an element.
01194     ///\param key The key to search for.
01195     ///\return An iterator pointing to the element or end() if not found.
01196     //*********************************************************************
01197     const_iterator find(key_parameter_t key) const
01198     {
01199       return const_iterator(*this, find_node(root_node, key));
01200     }
01201 
01202     //*********************************************************************
01203     /// Inserts a value to the multimap.
01204     /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
01205     ///\param value    The value to insert.
01206     //*********************************************************************
01207     iterator insert(const value_type& value)
01208     {
01209       // Default to no inserted node
01210       Node* inserted_node = std::nullptr;
01211 
01212       ETL_ASSERT(!full(), ETL_ERROR(multimap_full));
01213 
01214       // Get next available free node
01215       Data_Node& node = allocate_data_node(value);
01216 
01217       // Obtain the inserted node (might be std::nullptr if node was a duplicate)
01218       inserted_node = insert_node(root_node, node);
01219 
01220       // Insert node into tree and return iterator to new node location in tree
01221       return iterator(*this, inserted_node);
01222     }
01223 
01224     //*********************************************************************
01225     /// Inserts a value to the multimap starting at the position recommended.
01226     /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
01227     ///\param position The position that would precede the value to insert.
01228     ///\param value    The value to insert.
01229     //*********************************************************************
01230     iterator insert(iterator /*position*/, const value_type& value)
01231     {
01232       // Ignore position provided and just do a normal insert
01233       return insert(value);
01234     }
01235 
01236     //*********************************************************************
01237     /// Inserts a value to the multimap starting at the position recommended.
01238     /// If asserts or exceptions are enabled, emits map_full if the multimap is already full.
01239     ///\param position The position that would precede the value to insert.
01240     ///\param value    The value to insert.
01241     //*********************************************************************
01242     iterator insert(const_iterator /*position*/, const value_type& value)
01243     {
01244       // Ignore position provided and just do a normal insert
01245       return insert(value);
01246     }
01247 
01248     //*********************************************************************
01249     /// Inserts a range of values to the multimap.
01250     /// If asserts or exceptions are enabled, emits map_full if the multimap does not have enough free space.
01251     ///\param position The position to insert at.
01252     ///\param first    The first element to add.
01253     ///\param last     The last + 1 element to add.
01254     //*********************************************************************
01255     template <class TIterator>
01256     void insert(TIterator first, TIterator last)
01257     {
01258       while (first != last)
01259       {
01260         insert(*first++);
01261       }
01262     }
01263 
01264     //*********************************************************************
01265     /// Returns an iterator pointing to the first element in the container
01266     /// whose key is not considered to go before the key provided or end()
01267     /// if all keys are considered to go before the key provided.
01268     ///\return An iterator pointing to the element not before key or end()
01269     //*********************************************************************
01270     iterator lower_bound(key_parameter_t key)
01271     {
01272       return iterator(*this, find_lower_node(root_node, key));
01273     }
01274 
01275     //*********************************************************************
01276     /// Returns a const_iterator pointing to the first element in the
01277     /// container whose key is not considered to go before the key provided
01278     /// or end() if all keys are considered to go before the key provided.
01279     ///\return An const_iterator pointing to the element not before key or end()
01280     //*********************************************************************
01281     const_iterator lower_bound(key_parameter_t key) const
01282     {
01283       return const_iterator(*this, find_lower_node(root_node, key));
01284     }
01285 
01286     //*********************************************************************
01287     /// Returns an iterator pointing to the first element in the container
01288     /// whose key is not considered to go after the key provided or end()
01289     /// if all keys are considered to go after the key provided.
01290     ///\return An iterator pointing to the element after key or end()
01291     //*********************************************************************
01292     iterator upper_bound(key_parameter_t key)
01293     {
01294       return iterator(*this, find_upper_node(root_node, key));
01295     }
01296 
01297     //*********************************************************************
01298     /// Returns a const_iterator pointing to the first element in the
01299     /// container whose key is not considered to go after the key provided
01300     /// or end() if all keys are considered to go after the key provided.
01301     ///\return An const_iterator pointing to the element after key or end()
01302     //*********************************************************************
01303     const_iterator upper_bound(key_parameter_t key) const
01304     {
01305       return const_iterator(*this, find_upper_node(root_node, key));
01306     }
01307 
01308     //*************************************************************************
01309     /// Assignment operator.
01310     //*************************************************************************
01311     imultimap& operator = (const imultimap& rhs)
01312     {
01313       // Skip if doing self assignment
01314       if (this != &rhs)
01315       {
01316         assign(rhs.cbegin(), rhs.cend());
01317       }
01318 
01319       return *this;
01320     }
01321 
01322   protected:
01323 
01324     //*************************************************************************
01325     /// Constructor.
01326     //*************************************************************************
01327     imultimap(etl::ipool& node_pool, size_t max_size_)
01328       : multimap_base(max_size_)
01329       , p_node_pool(&node_pool)
01330     {
01331     }
01332 
01333     //*************************************************************************
01334     /// Initialise the multimap.
01335     //*************************************************************************
01336     void initialise()
01337     {
01338       erase(begin(), end());
01339     }
01340 
01341   private:
01342 
01343     //*************************************************************************
01344     /// Allocate a Data_Node.
01345     //*************************************************************************
01346     Data_Node& allocate_data_node(value_type value)
01347     {
01348       Data_Node& node = *p_node_pool->allocate<Data_Node>();
01349       ::new (&node.value) const value_type(value);
01350       ++construct_count;
01351       return node;
01352     }
01353 
01354     //*************************************************************************
01355     /// Destroy a Data_Node.
01356     //*************************************************************************
01357     void destroy_data_node(Data_Node& node)
01358     {
01359       node.value.~value_type();
01360       p_node_pool->release(&node);
01361       --construct_count;
01362     }
01363 
01364     //*************************************************************************
01365     /// Count the nodes that match the key provided
01366     //*************************************************************************
01367     size_type count_nodes(key_parameter_t key) const
01368     {
01369       // Number of nodes that match the key provided result
01370       size_type result = 0;
01371 
01372       // Find lower and upper nodes for the key provided
01373       const Node* lower = find_lower_node(root_node, key);
01374       const Node* upper = find_upper_node(root_node, key);
01375 
01376       // Loop from lower node to upper node and find nodes that match
01377       while (lower != upper)
01378       {
01379         // Downcast found to Data_Node class for comparison and other operations
01380         const Data_Node& data_node = imultimap::data_cast(*lower);
01381 
01382         if (!node_comp(key, data_node) && !node_comp(data_node, key))
01383         {
01384           // This node matches the key provided
01385           ++result;
01386         }
01387 
01388         // Move on to the next node
01389         next_node(lower);
01390       }
01391 
01392       // Return the number of nodes that match
01393       return result;
01394     }
01395 
01396     //*************************************************************************
01397     /// Find the value matching the node provided
01398     //*************************************************************************
01399     Node* find_node(Node* position, key_parameter_t key) const
01400     {
01401       Node* found = std::nullptr;
01402       while (position)
01403       {
01404         // Downcast found to Data_Node class for comparison and other operations
01405         Data_Node& data_node = imultimap::data_cast(*position);
01406         // Compare the node value to the current position value
01407         if (node_comp(key, data_node))
01408         {
01409           // Keep searching for the node on the left
01410           position = position->children[kLeft];
01411         }
01412         else if (node_comp(data_node, key))
01413         {
01414           // Keep searching for the node on the right
01415           position = position->children[kRight];
01416         }
01417         else
01418         {
01419           // We found one, keep looking for more on the left
01420           found = position;
01421           position = position->children[kLeft];
01422         }
01423       }
01424 
01425       // Return the node found (might be std::nullptr)
01426       return found;
01427     }
01428 
01429     //*************************************************************************
01430     /// Find the value matching the node provided
01431     //*************************************************************************
01432     const Node* find_node(const Node* position, key_parameter_t key) const
01433     {
01434       const Node* found = std::nullptr;
01435       while (position)
01436       {
01437         // Downcast found to Data_Node class for comparison and other operations
01438         const Data_Node& data_node = imultimap::data_cast(*position);
01439         // Compare the node value to the current position value
01440         if (node_comp(key, data_node))
01441         {
01442           // Keep searching for the node on the left
01443           position = position->children[kLeft];
01444         }
01445         else if (node_comp(data_node, key))
01446         {
01447           // Keep searching for the node on the right
01448           position = position->children[kRight];
01449         }
01450         else
01451         {
01452           // We found one, keep looking for more on the left
01453           found = position;
01454           position = position->children[kLeft];
01455         }
01456       }
01457 
01458       // Return the node found (might be std::nullptr)
01459       return found;
01460     }
01461 
01462     //*************************************************************************
01463     /// Find the node whose key is not considered to go before the key provided
01464     //*************************************************************************
01465     Node* find_lower_node(Node* position, key_parameter_t key) const
01466     {
01467       // Something at this position? keep going
01468       Node* lower_node = std::nullptr;
01469       while (position)
01470       {
01471         // Downcast lower node to Data_Node reference for key comparisons
01472         Data_Node& data_node = imultimap::data_cast(*position);
01473         // Compare the key value to the current lower node key value
01474         if (node_comp(key, data_node))
01475         {
01476           lower_node = position;
01477           if (position->children[kLeft])
01478           {
01479             position = position->children[kLeft];
01480           }
01481           else
01482           {
01483             // Found lowest node
01484             break;
01485           }
01486         }
01487         else if (node_comp(data_node, key))
01488         {
01489           position = position->children[kRight];
01490         }
01491         else
01492         {
01493           // Make note of current position, but keep looking to left for more
01494           lower_node = position;
01495           position = position->children[kLeft];
01496         }
01497       }
01498 
01499       // Return the lower_node position found
01500       return lower_node;
01501     }
01502 
01503     //*************************************************************************
01504     /// Find the node whose key is considered to go after the key provided
01505     //*************************************************************************
01506     Node* find_upper_node(Node* position, key_parameter_t key) const
01507     {
01508       // Keep track of parent of last upper node
01509       Node* upper_node = std::nullptr;
01510       // Has an equal node been found? start with no
01511       bool found = false;
01512       while (position)
01513       {
01514         // Downcast position to Data_Node reference for key comparisons
01515         Data_Node& data_node = imultimap::data_cast(*position);
01516         // Compare the key value to the current upper node key value
01517         if (node_comp(data_node, key))
01518         {
01519           position = position->children[kRight];
01520         }
01521         else if (node_comp(key, data_node))
01522         {
01523           upper_node = position;
01524           // If a node equal to key hasn't been found go left
01525           if (!found && position->children[kLeft])
01526           {
01527             position = position->children[kLeft];
01528           }
01529           else
01530           {
01531             break;
01532           }
01533         }
01534         else
01535         {
01536           // We found an equal item, break on next bigger item
01537           found = true;
01538           next_node(position);
01539         }
01540       }
01541 
01542       // Return the upper node position found (might be std::nullptr)
01543       return upper_node;
01544     }
01545 
01546     //*************************************************************************
01547     /// Insert a node.
01548     //*************************************************************************
01549     Node* insert_node(Node*& position, Data_Node& node)
01550     {
01551       // Find the location where the node belongs
01552       Node* found = position;
01553 
01554       // Was position provided not empty? then find where the node belongs
01555       if (position)
01556       {
01557         // Find the critical parent node (default to std::nullptr)
01558         Node* critical_parent_node = std::nullptr;
01559         Node* critical_node = root_node;
01560 
01561         while (found)
01562         {
01563           // Search for critical weight node (all nodes whose weight factor
01564           // is set to kNeither (balanced)
01565           if (kNeither != found->weight)
01566           {
01567             critical_node = found;
01568           }
01569 
01570           // Downcast found to Data_Node class for comparison and other operations
01571           Data_Node& found_data_node = imultimap::data_cast(*found);
01572 
01573           // Is the node provided to the left of the current position?
01574           if (node_comp(node, found_data_node))
01575           {
01576             // Update direction taken to insert new node in parent node
01577             found->dir = kLeft;
01578           }
01579           // Is the node provided to the right of the current position?
01580           else if (node_comp(found_data_node, node))
01581           {
01582             // Update direction taken to insert new node in parent node
01583             found->dir = kRight;
01584           }
01585           else
01586           {
01587             // Update direction taken to insert new node in parent (and
01588             // duplicate) node to the right.
01589             found->dir = kRight;
01590           }
01591 
01592           // Is there a child of this parent node?
01593           if (found->children[found->dir])
01594           {
01595             // Will this node be the parent of the next critical node whose
01596             // weight factor is set to kNeither (balanced)?
01597             if (kNeither != found->children[found->dir]->weight)
01598             {
01599               critical_parent_node = found;
01600             }
01601 
01602             // Keep looking for empty spot to insert new node
01603             found = found->children[found->dir];
01604           }
01605           else
01606           {
01607             // Attach node as a child of the parent node found
01608             attach_node(found, found->children[found->dir], node);
01609 
01610             // Return newly added node
01611             found = found->children[found->dir];
01612 
01613             // Exit loop
01614             break;
01615           }
01616         }
01617 
01618         // Was a critical node found that should be checked for balance?
01619         if (critical_node)
01620         {
01621           if (critical_parent_node == std::nullptr && critical_node == root_node)
01622           {
01623             balance_node(root_node);
01624           }
01625           else if (critical_parent_node == std::nullptr && critical_node == position)
01626           {
01627             balance_node(position);
01628           }
01629           else
01630           {
01631             balance_node(critical_parent_node->children[critical_parent_node->dir]);
01632           }
01633         }
01634       }
01635       else
01636       {
01637         // Attach node to current position (which is assumed to be root)
01638         attach_node(std::nullptr, position, node);
01639 
01640         // Return newly added node at current position
01641         found = position;
01642       }
01643 
01644       // Return the node found (might be std::nullptr)
01645       return found;
01646     }
01647 
01648     //*************************************************************************
01649     /// Remove the node specified from somewhere starting at the position
01650     /// provided
01651     //*************************************************************************
01652     void remove_node(Node* node)
01653     {
01654       // If valid found node was provided then proceed with steps 1 through 5
01655       if (node)
01656       {
01657         // Downcast found node provided to Data_Node class
01658         Data_Node& data_node = imultimap::data_cast(*node);
01659 
01660         // Keep track of node as found node
01661         Node* found = node;
01662 
01663         // Step 1: Mark path from node provided back to the root node using the
01664         // internal temporary dir member value and using the parent pointer. This
01665         // will allow us to avoid recursion in finding the node in a tree that
01666         //might contain duplicate keys to be found.
01667         while (node)
01668         {
01669           if (node->parent)
01670           {
01671             // Which direction does parent use to get to this node?
01672             node->parent->dir =
01673               node->parent->children[kLeft] == node ? kLeft : kRight;
01674 
01675             // Make this nodes parent the next node
01676             node = node->parent;
01677           }
01678           else
01679           {
01680             // Root node found - break loop
01681             break;
01682           }
01683         }
01684 
01685         // Step 2: Follow the path provided above until we reach the node
01686         // provided and look for the balance node to start rebalancing the tree
01687         // from (up to the replacement node that will be found in step 3)
01688         Node* balance = root_node;
01689         while (node)
01690         {
01691           // Did we reach the node provided originally (found) then go to step 3
01692           if (node == found)
01693           {
01694             // Update the direction towards a replacement node at the found node
01695             node->dir = node->children[kLeft] ? kLeft : kRight;
01696 
01697             // Exit loop and proceed with step 3
01698             break;
01699           }
01700           else
01701           {
01702             // If this nodes weight is kNeither or we are taking the shorter path
01703             // to the next node and our sibling (on longer path) is balanced then
01704             // we need to update the balance node to this node but all our
01705             // ancestors will not require rebalancing
01706             if ((node->weight == kNeither) ||
01707               (node->weight == (1 - node->dir) &&
01708                 node->children[1 - node->dir]->weight == kNeither))
01709             {
01710               // Update balance node to this node
01711               balance = node;
01712             }
01713 
01714             // Keep searching for found in the direction provided in step 1
01715             node = node->children[node->dir];
01716           }
01717         }
01718         // The value for node should not be std::nullptr at this point otherwise
01719         // step 1 failed to provide the correct path to found. Step 5 will fail
01720         // (probably subtly) if node should be std::nullptr at this point
01721 
01722         // Step 3: Find the node (node should be equal to found at this point)
01723         // to replace found with (might end up equal to found) while also
01724         // continuing to update balance the same as in step 2 above.
01725         while (node)
01726         {
01727           // Replacement node found if its missing a child in the replace->dir
01728           // value set at the end of step 2 above
01729           if (node->children[node->dir] == std::nullptr)
01730           {
01731             // Exit loop once node to replace found is determined
01732             break;
01733           }
01734 
01735           // If this nodes weight is kNeither or we are taking the shorter path
01736           // to the next node and our sibling (on longer path) is balanced then
01737           // we need to update the balance node to this node but all our
01738           // ancestors will not require rebalancing
01739           if ((node->weight == kNeither) ||
01740             (node->weight == (1 - node->dir) &&
01741               node->children[1 - node->dir]->weight == kNeither))
01742           {
01743             // Update balance node to this node
01744             balance = node;
01745           }
01746 
01747           // Keep searching for replacement node in the direction specified above
01748           node = node->children[node->dir];
01749 
01750           // Downcast node to Data_Node class for comparison operations
01751           Data_Node& replace_data_node = imultimap::data_cast(*node);
01752 
01753           // Compare the key provided to the replace data node key
01754           if (node_comp(data_node, replace_data_node))
01755           {
01756             // Update the direction to the replace node
01757             node->dir = kLeft;
01758           }
01759           else if (node_comp(replace_data_node, data_node))
01760           {
01761             // Update the direction to the replace node
01762             node->dir = kRight;
01763           }
01764           else
01765           {
01766             // Update the direction to the replace node
01767             node->dir = node->children[kLeft] ? kLeft : kRight;
01768           }
01769         } // while(node)
01770 
01771           // Step 4: Update weights from balance to parent of node determined
01772           // in step 3 above rotating (2 or 3 node rotations) as needed.
01773         while (balance)
01774         {
01775           // Break when balance node reaches the parent of replacement node
01776           if (balance->children[balance->dir] == std::nullptr)
01777           {
01778             break;
01779           }
01780 
01781           // If balance node is balanced already (kNeither) then just imbalance
01782           // the node in the opposite direction of the node being removed
01783           if (balance->weight == kNeither)
01784           {
01785             balance->weight = 1 - balance->dir;
01786           }
01787           // If balance node is imbalanced in the opposite direction of the
01788           // node being removed then the node now becomes balanced
01789           else if (balance->weight == balance->dir)
01790           {
01791             balance->weight = kNeither;
01792           }
01793           // Otherwise a rotation is required at this node
01794           else
01795           {
01796             int weight = balance->children[1 - balance->dir]->weight;
01797             // Perform a 3 node rotation if weight is same as balance->dir
01798             if (weight == balance->dir)
01799             {
01800               // Is the root node being rebalanced (no parent)
01801               if (balance->parent == std::nullptr)
01802               {
01803                 rotate_3node(root_node, 1 - balance->dir,
01804                   balance->children[1 - balance->dir]->children[balance->dir]->weight);
01805               }
01806               else
01807               {
01808                 rotate_3node(balance->parent->children[balance->parent->dir], 1 - balance->dir,
01809                   balance->children[1 - balance->dir]->children[balance->dir]->weight);
01810               }
01811             }
01812             // Already balanced, rebalance and make it heavy in opposite
01813             // direction of the node being removed
01814             else if (weight == kNeither)
01815             {
01816               // Is the root node being rebalanced (no parent)
01817               if (balance->parent == std::nullptr)
01818               {
01819                 rotate_2node(root_node, 1 - balance->dir);
01820                 root_node->weight = balance->dir;
01821               }
01822               else
01823               {
01824                 // Balance parent might change during rotate, keep local copy
01825                 // to old parent so its weight can be updated after the 2 node
01826                 // rotate is completed
01827                 Node* old_parent = balance->parent;
01828                 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
01829                 old_parent->children[old_parent->dir]->weight = balance->dir;
01830               }
01831               // Update balance node weight in opposite direction of node removed
01832               balance->weight = 1 - balance->dir;
01833             }
01834             // Rebalance and leave it balanced
01835             else
01836             {
01837               // Is the root node being rebalanced (no parent)
01838               if (balance->parent == std::nullptr)
01839               {
01840                 rotate_2node(root_node, 1 - balance->dir);
01841               }
01842               else
01843               {
01844                 rotate_2node(balance->parent->children[balance->parent->dir], 1 - balance->dir);
01845               }
01846             }
01847           }
01848 
01849           // Next balance node to consider
01850           balance = balance->children[balance->dir];
01851         } // while(balance)
01852 
01853           // Step 5: Swap found with node (replacement)
01854         if (found->parent)
01855         {
01856           // Handle traditional case
01857           detach_node(found->parent->children[found->parent->dir],
01858             node->parent->children[node->parent->dir]);
01859         }
01860         // Handle root node removal
01861         else
01862         {
01863           // Valid replacement node for root node being removed?
01864           if (node->parent)
01865           {
01866             detach_node(root_node, node->parent->children[node->parent->dir]);
01867           }
01868           else
01869           {
01870             // Found node and replacement node are both root node
01871             detach_node(root_node, root_node);
01872           }
01873         }
01874 
01875         // One less.
01876         --current_size;
01877 
01878         // Destroy the node detached above
01879         destroy_data_node(data_node);
01880       } // if(found)
01881     }
01882 
01883     // Disable copy construction.
01884     imultimap(const imultimap&);
01885   };
01886 
01887   //*************************************************************************
01888   /// A templated multimap implementation that uses a fixed size buffer.
01889   //*************************************************************************
01890   template <typename TKey, typename TValue, const size_t MAX_SIZE_, typename TCompare = std::less<TKey> >
01891   class multimap : public etl::imultimap<TKey, TValue, TCompare>
01892   {
01893   public:
01894 
01895     static const size_t MAX_SIZE = MAX_SIZE_;
01896 
01897     //*************************************************************************
01898     /// Default constructor.
01899     //*************************************************************************
01900     multimap()
01901       : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
01902     {
01903       etl::imultimap<TKey, TValue, TCompare>::initialise();
01904     }
01905 
01906     //*************************************************************************
01907     /// Copy constructor.
01908     //*************************************************************************
01909     multimap(const multimap& other)
01910       : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
01911     {
01912       etl::imultimap<TKey, TValue, TCompare>::assign(other.cbegin(), other.cend());
01913     }
01914 
01915     //*************************************************************************
01916     /// Constructor, from an iterator range.
01917     ///\tparam TIterator The iterator type.
01918     ///\param first The iterator to the first element.
01919     ///\param last  The iterator to the last element + 1.
01920     //*************************************************************************
01921     template <typename TIterator>
01922     multimap(TIterator first, TIterator last)
01923       : etl::imultimap<TKey, TValue, TCompare>(node_pool, MAX_SIZE)
01924     {
01925       etl::imultimap<TKey, TValue, TCompare>::assign(first, last);
01926     }
01927 
01928     //*************************************************************************
01929     /// Destructor.
01930     //*************************************************************************
01931     ~multimap()
01932     {
01933       etl::imultimap<TKey, TValue, TCompare>::initialise();
01934     }
01935 
01936     //*************************************************************************
01937     /// Assignment operator.
01938     //*************************************************************************
01939     multimap& operator = (const multimap& rhs)
01940     {
01941       // Skip if doing self assignment
01942       if (this != &rhs)
01943       {
01944         etl::imultimap<TKey, TValue, TCompare>::assign(rhs.cbegin(), rhs.cend());
01945       }
01946 
01947       return *this;
01948     }
01949 
01950   private:
01951 
01952     /// The pool of data nodes used for the multimap.
01953     etl::pool<typename etl::imultimap<TKey, TValue, TCompare>::Data_Node, MAX_SIZE> node_pool;
01954   };
01955 }
01956 
01957 //***************************************************************************
01958 /// Equal operator.
01959 ///\param lhs Reference to the first lookup.
01960 ///\param rhs Reference to the second lookup.
01961 ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>
01962 ///\ingroup lookup
01963 //***************************************************************************
01964 template <typename TKey, typename TMapped, typename TKeyCompare>
01965 bool operator ==(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
01966 {
01967   return (lhs.size() == rhs.size()) && std::equal(lhs.begin(), lhs.end(), rhs.begin());
01968 }
01969 
01970 //***************************************************************************
01971 /// Not equal operator.
01972 ///\param lhs Reference to the first lookup.
01973 ///\param rhs Reference to the second lookup.
01974 ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>
01975 ///\ingroup lookup
01976 //***************************************************************************
01977 template <typename TKey, typename TMapped, typename TKeyCompare>
01978 bool operator !=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
01979 {
01980   return !(lhs == rhs);
01981 }
01982 
01983 //*************************************************************************
01984 /// Less than operator.
01985 ///\param lhs Reference to the first list.
01986 ///\param rhs Reference to the second list.
01987 ///\return <b>true</b> if the first list is lexicographically less than the
01988 /// second, otherwise <b>false</b>.
01989 //*************************************************************************
01990 template <typename TKey, typename TMapped, typename TKeyCompare>
01991 bool operator <(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
01992 {
01993   return std::lexicographical_compare(lhs.begin(),
01994     lhs.end(),
01995     rhs.begin(),
01996     rhs.end());
01997 }
01998 
01999 //*************************************************************************
02000 /// Greater than operator.
02001 ///\param lhs Reference to the first list.
02002 ///\param rhs Reference to the second list.
02003 ///\return <b>true</b> if the first list is lexicographically greater than the
02004 /// second, otherwise <b>false</b>.
02005 //*************************************************************************
02006 template <typename TKey, typename TMapped, typename TKeyCompare>
02007 bool operator >(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
02008 {
02009   return (rhs < lhs);
02010 }
02011 
02012 //*************************************************************************
02013 /// Less than or equal operator.
02014 ///\param lhs Reference to the first list.
02015 ///\param rhs Reference to the second list.
02016 ///\return <b>true</b> if the first list is lexicographically less than or equal
02017 /// to the second, otherwise <b>false</b>.
02018 //*************************************************************************
02019 template <typename TKey, typename TMapped, typename TKeyCompare>
02020 bool operator <=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
02021 {
02022   return !(lhs > rhs);
02023 }
02024 
02025 //*************************************************************************
02026 /// Greater than or equal operator.
02027 ///\param lhs Reference to the first list.
02028 ///\param rhs Reference to the second list.
02029 ///\return <b>true</b> if the first list is lexicographically greater than or
02030 /// equal to the second, otherwise <b>false</b>.
02031 //*************************************************************************
02032 template <typename TKey, typename TMapped, typename TKeyCompare>
02033 bool operator >=(const etl::imultimap<TKey, TMapped, TKeyCompare>& lhs, const etl::imultimap<TKey, TMapped, TKeyCompare>& rhs)
02034 {
02035   return !(lhs < rhs);
02036 }
02037 
02038 #ifdef ETL_COMPILER_MICROSOFT
02039 #define min(a,b) (((a) < (b)) ? (a) : (b))
02040 #endif
02041 
02042 #undef ETL_FILE
02043 
02044 #endif
02045