aboutsummaryrefslogtreecommitdiff
path: root/include/EASTL/internal/red_black_tree.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/EASTL/internal/red_black_tree.h')
-rw-r--r--include/EASTL/internal/red_black_tree.h2366
1 files changed, 0 insertions, 2366 deletions
diff --git a/include/EASTL/internal/red_black_tree.h b/include/EASTL/internal/red_black_tree.h
deleted file mode 100644
index 5b29b7c..0000000
--- a/include/EASTL/internal/red_black_tree.h
+++ /dev/null
@@ -1,2366 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////
-// Copyright (c) Electronic Arts Inc. All rights reserved.
-/////////////////////////////////////////////////////////////////////////////
-
-
-#ifndef EASTL_RED_BLACK_TREE_H
-#define EASTL_RED_BLACK_TREE_H
-
-
-#include <EABase/eabase.h>
-#if defined(EA_PRAGMA_ONCE_SUPPORTED)
- #pragma once
-#endif
-
-#include <EASTL/internal/config.h>
-#include <EASTL/type_traits.h>
-#include <EASTL/allocator.h>
-#include <EASTL/iterator.h>
-#include <EASTL/utility.h>
-#include <EASTL/algorithm.h>
-#include <EASTL/initializer_list.h>
-#include <EASTL/tuple.h>
-
-EA_DISABLE_ALL_VC_WARNINGS()
-#include <new>
-#include <stddef.h>
-EA_RESTORE_ALL_VC_WARNINGS()
-
-
-// 4512 - 'class' : assignment operator could not be generated
-// 4530 - C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
-// 4571 - catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught.
-EA_DISABLE_VC_WARNING(4512 4530 4571);
-
-
-namespace eastl
-{
-
- /// EASTL_RBTREE_DEFAULT_NAME
- ///
- /// Defines a default container name in the absence of a user-provided name.
- ///
- #ifndef EASTL_RBTREE_DEFAULT_NAME
- #define EASTL_RBTREE_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " rbtree" // Unless the user overrides something, this is "EASTL rbtree".
- #endif
-
-
- /// EASTL_RBTREE_DEFAULT_ALLOCATOR
- ///
- #ifndef EASTL_RBTREE_DEFAULT_ALLOCATOR
- #define EASTL_RBTREE_DEFAULT_ALLOCATOR allocator_type(EASTL_RBTREE_DEFAULT_NAME)
- #endif
-
-
- /// EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
- ///
- #ifndef EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
- #define EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR 0
- #endif
-
-
- /// RBTreeColor
- ///
- enum RBTreeColor
- {
- kRBTreeColorRed,
- kRBTreeColorBlack
- };
-
-
-
- /// RBTreeColor
- ///
- enum RBTreeSide
- {
- kRBTreeSideLeft,
- kRBTreeSideRight
- };
-
-
-
- /// rbtree_node_base
- ///
- /// We define a rbtree_node_base separately from rbtree_node (below), because it
- /// allows us to have non-templated operations, and it makes it so that the
- /// rbtree anchor node doesn't carry a T with it, which would waste space and
- /// possibly lead to surprising the user due to extra Ts existing that the user
- /// didn't explicitly create. The downside to all of this is that it makes debug
- /// viewing of an rbtree harder, given that the node pointers are of type
- /// rbtree_node_base and not rbtree_node.
- ///
- struct rbtree_node_base
- {
- typedef rbtree_node_base this_type;
-
- public:
- this_type* mpNodeRight; // Declared first because it is used most often.
- this_type* mpNodeLeft;
- this_type* mpNodeParent;
- char mColor; // We only need one bit here, would be nice if we could stuff that bit somewhere else.
- };
-
-
- /// rbtree_node
- ///
- template <typename Value>
- struct rbtree_node : public rbtree_node_base
- {
- Value mValue; // For set and multiset, this is the user's value, for map and multimap, this is a pair of key/value.
-
- // This type is never constructed, so to avoid a MSVC warning we "delete" the copy constructor.
- //
- // Potentially we could provide a constructor that would satisfy the compiler and change the code to use this constructor
- // instead of constructing mValue in place within an unconstructed rbtree_node.
- #if defined(_MSC_VER)
- rbtree_node(const rbtree_node&) = delete;
- #endif
- };
-
-
-
-
- // rbtree_node_base functions
- //
- // These are the fundamental functions that we use to maintain the
- // tree. The bulk of the work of the tree maintenance is done in
- // these functions.
- //
- EASTL_API rbtree_node_base* RBTreeIncrement (const rbtree_node_base* pNode);
- EASTL_API rbtree_node_base* RBTreeDecrement (const rbtree_node_base* pNode);
- EASTL_API rbtree_node_base* RBTreeGetMinChild (const rbtree_node_base* pNode);
- EASTL_API rbtree_node_base* RBTreeGetMaxChild (const rbtree_node_base* pNode);
- EASTL_API size_t RBTreeGetBlackCount(const rbtree_node_base* pNodeTop,
- const rbtree_node_base* pNodeBottom);
- EASTL_API void RBTreeInsert ( rbtree_node_base* pNode,
- rbtree_node_base* pNodeParent,
- rbtree_node_base* pNodeAnchor,
- RBTreeSide insertionSide);
- EASTL_API void RBTreeErase ( rbtree_node_base* pNode,
- rbtree_node_base* pNodeAnchor);
-
-
-
-
-
-
-
- /// rbtree_iterator
- ///
- template <typename T, typename Pointer, typename Reference>
- struct rbtree_iterator
- {
- typedef rbtree_iterator<T, Pointer, Reference> this_type;
- typedef rbtree_iterator<T, T*, T&> iterator;
- typedef rbtree_iterator<T, const T*, const T&> const_iterator;
- typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
- typedef ptrdiff_t difference_type;
- typedef T value_type;
- typedef rbtree_node_base base_node_type;
- typedef rbtree_node<T> node_type;
- typedef Pointer pointer;
- typedef Reference reference;
- typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category;
-
- public:
- node_type* mpNode;
-
- public:
- rbtree_iterator();
- explicit rbtree_iterator(const node_type* pNode);
- rbtree_iterator(const iterator& x);
- rbtree_iterator& operator=(const iterator& x);
-
- reference operator*() const;
- pointer operator->() const;
-
- rbtree_iterator& operator++();
- rbtree_iterator operator++(int);
-
- rbtree_iterator& operator--();
- rbtree_iterator operator--(int);
-
- }; // rbtree_iterator
-
-
- ///////////////////////////////////////////////////////////////////////////////
- // rb_base_compare_ebo
- //
- // Utilizes the "empty base-class optimization" to reduce the size of the rbtree
- // when its Compare template argument is an empty class.
- ///////////////////////////////////////////////////////////////////////////////
-
- template <typename Compare, bool /*isEmpty*/ = is_empty<Compare>::value>
- struct rb_base_compare_ebo
- {
- protected:
- rb_base_compare_ebo() : mCompare() {}
- rb_base_compare_ebo(const Compare& compare) : mCompare(compare) {}
-
- Compare& get_compare() { return mCompare; }
- const Compare& get_compare() const { return mCompare; }
-
- template <typename T>
- bool compare(const T& lhs, const T& rhs)
- {
- return mCompare(lhs, rhs);
- }
-
- template <typename T>
- bool compare(const T& lhs, const T& rhs) const
- {
- return mCompare(lhs, rhs);
- }
-
- private:
- Compare mCompare;
- };
-
- template <typename Compare>
- struct rb_base_compare_ebo<Compare, true> : private Compare
- {
- protected:
- rb_base_compare_ebo() {}
- rb_base_compare_ebo(const Compare& compare) : Compare(compare) {}
-
- Compare& get_compare() { return *this; }
- const Compare& get_compare() const { return *this; }
-
- template <typename T>
- bool compare(const T& lhs, const T& rhs)
- {
- return Compare::operator()(lhs, rhs);
- }
-
- template <typename T>
- bool compare(const T& lhs, const T& rhs) const
- {
- return Compare::operator()(lhs, rhs);
- }
- };
-
-
-
- ///////////////////////////////////////////////////////////////////////////////
- // rb_base
- //
- // This class allows us to use a generic rbtree as the basis of map, multimap,
- // set, and multiset transparently. The vital template parameters for this are
- // the ExtractKey and the bUniqueKeys parameters.
- //
- // If the rbtree has a value type of the form pair<T1, T2> (i.e. it is a map or
- // multimap and not a set or multiset) and a key extraction policy that returns
- // the first part of the pair, the rbtree gets a mapped_type typedef.
- // If it satisfies those criteria and also has unique keys, then it also gets an
- // operator[] (which only map and set have and multimap and multiset don't have).
- //
- ///////////////////////////////////////////////////////////////////////////////
-
-
-
- /// rb_base
- /// This specialization is used for 'set'. In this case, Key and Value
- /// will be the same as each other and ExtractKey will be eastl::use_self.
- ///
- template <typename Key, typename Value, typename Compare, typename ExtractKey, bool bUniqueKeys, typename RBTree>
- struct rb_base : public rb_base_compare_ebo<Compare>
- {
- typedef ExtractKey extract_key;
-
- protected:
- using rb_base_compare_ebo<Compare>::compare;
- using rb_base_compare_ebo<Compare>::get_compare;
-
- public:
- rb_base() {}
- rb_base(const Compare& compare) : rb_base_compare_ebo<Compare>(compare) {}
- };
-
-
- /// rb_base
- /// This class is used for 'multiset'.
- /// In this case, Key and Value will be the same as each
- /// other and ExtractKey will be eastl::use_self.
- ///
- template <typename Key, typename Value, typename Compare, typename ExtractKey, typename RBTree>
- struct rb_base<Key, Value, Compare, ExtractKey, false, RBTree> : public rb_base_compare_ebo<Compare>
- {
- typedef ExtractKey extract_key;
-
- protected:
- using rb_base_compare_ebo<Compare>::compare;
- using rb_base_compare_ebo<Compare>::get_compare;
-
- public:
- rb_base() {}
- rb_base(const Compare& compare) : rb_base_compare_ebo<Compare>(compare) {}
- };
-
-
- /// rb_base
- /// This specialization is used for 'map'.
- ///
- template <typename Key, typename Pair, typename Compare, typename RBTree>
- struct rb_base<Key, Pair, Compare, eastl::use_first<Pair>, true, RBTree> : public rb_base_compare_ebo<Compare>
- {
- typedef eastl::use_first<Pair> extract_key;
-
- using rb_base_compare_ebo<Compare>::compare;
- using rb_base_compare_ebo<Compare>::get_compare;
-
- public:
- rb_base() {}
- rb_base(const Compare& compare) : rb_base_compare_ebo<Compare>(compare) {}
- };
-
-
- /// rb_base
- /// This specialization is used for 'multimap'.
- ///
- template <typename Key, typename Pair, typename Compare, typename RBTree>
- struct rb_base<Key, Pair, Compare, eastl::use_first<Pair>, false, RBTree> : public rb_base_compare_ebo<Compare>
- {
- typedef eastl::use_first<Pair> extract_key;
-
- using rb_base_compare_ebo<Compare>::compare;
- using rb_base_compare_ebo<Compare>::get_compare;
-
- public:
- rb_base() {}
- rb_base(const Compare& compare) : rb_base_compare_ebo<Compare>(compare) {}
- };
-
-
- /// rbtree
- ///
- /// rbtree is the red-black tree basis for the map, multimap, set, and multiset
- /// containers. Just about all the work of those containers is done here, and
- /// they are merely a shell which sets template policies that govern the code
- /// generation for this rbtree.
- ///
- /// This rbtree implementation is pretty much the same as all other modern
- /// rbtree implementations, as the topic is well known and researched. We may
- /// choose to implement a "relaxed balancing" option at some point in the
- /// future if it is deemed worthwhile. Most rbtree implementations don't do this.
- ///
- /// The primary rbtree member variable is mAnchor, which is a node_type and
- /// acts as the end node. However, like any other node, it has mpNodeLeft,
- /// mpNodeRight, and mpNodeParent members. We do the conventional trick of
- /// assigning begin() (left-most rbtree node) to mpNodeLeft, assigning
- /// 'end() - 1' (a.k.a. rbegin()) to mpNodeRight, and assigning the tree root
- /// node to mpNodeParent.
- ///
- /// Compare (functor): This is a comparison class which defaults to 'less'.
- /// It is a common STL thing which takes two arguments and returns true if
- /// the first is less than the second.
- ///
- /// ExtractKey (functor): This is a class which gets the key from a stored
- /// node. With map and set, the node is a pair, whereas with set and multiset
- /// the node is just the value. ExtractKey will be either eastl::use_first (map and multimap)
- /// or eastl::use_self (set and multiset).
- ///
- /// bMutableIterators (bool): true if rbtree::iterator is a mutable
- /// iterator, false if iterator and const_iterator are both const iterators.
- /// It will be true for map and multimap and false for set and multiset.
- ///
- /// bUniqueKeys (bool): true if the keys are to be unique, and false if there
- /// can be multiple instances of a given key. It will be true for set and map
- /// and false for multiset and multimap.
- ///
- /// To consider: Add an option for relaxed tree balancing. This could result
- /// in performance improvements but would require a more complicated implementation.
- ///
- ///////////////////////////////////////////////////////////////////////
- /// find_as
- /// In order to support the ability to have a tree of strings but
- /// be able to do efficiently lookups via char pointers (i.e. so they
- /// aren't converted to string objects), we provide the find_as
- /// function. This function allows you to do a find with a key of a
- /// type other than the tree's key type. See the find_as function
- /// for more documentation on this.
- ///
- template <typename Key, typename Value, typename Compare, typename Allocator,
- typename ExtractKey, bool bMutableIterators, bool bUniqueKeys>
- class rbtree
- : public rb_base<Key, Value, Compare, ExtractKey, bUniqueKeys,
- rbtree<Key, Value, Compare, Allocator, ExtractKey, bMutableIterators, bUniqueKeys> >
- {
- public:
- typedef ptrdiff_t difference_type;
- typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
- typedef Key key_type;
- typedef Value value_type;
- typedef rbtree_node<value_type> node_type;
- typedef value_type& reference;
- typedef const value_type& const_reference;
- typedef value_type* pointer;
- typedef const value_type* const_pointer;
-
- typedef typename type_select<bMutableIterators,
- rbtree_iterator<value_type, value_type*, value_type&>,
- rbtree_iterator<value_type, const value_type*, const value_type&> >::type iterator;
- typedef rbtree_iterator<value_type, const value_type*, const value_type&> const_iterator;
- typedef eastl::reverse_iterator<iterator> reverse_iterator;
- typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator;
-
- typedef Allocator allocator_type;
- typedef Compare key_compare;
- typedef typename type_select<bUniqueKeys, eastl::pair<iterator, bool>, iterator>::type insert_return_type; // map/set::insert return a pair, multimap/multiset::iterator return an iterator.
- typedef rbtree<Key, Value, Compare, Allocator,
- ExtractKey, bMutableIterators, bUniqueKeys> this_type;
- typedef rb_base<Key, Value, Compare, ExtractKey, bUniqueKeys, this_type> base_type;
- typedef integral_constant<bool, bUniqueKeys> has_unique_keys_type;
- typedef typename base_type::extract_key extract_key;
-
- protected:
- using base_type::compare;
- using base_type::get_compare;
-
- public:
- rbtree_node_base mAnchor; /// This node acts as end() and its mpLeft points to begin(), and mpRight points to rbegin() (the last node on the right).
- size_type mnSize; /// Stores the count of nodes in the tree (not counting the anchor node).
- allocator_type mAllocator; // To do: Use base class optimization to make this go away.
-
- public:
- // ctor/dtor
- rbtree();
- rbtree(const allocator_type& allocator);
- rbtree(const Compare& compare, const allocator_type& allocator = EASTL_RBTREE_DEFAULT_ALLOCATOR);
- rbtree(const this_type& x);
- rbtree(this_type&& x);
- rbtree(this_type&& x, const allocator_type& allocator);
-
- template <typename InputIterator>
- rbtree(InputIterator first, InputIterator last, const Compare& compare, const allocator_type& allocator = EASTL_RBTREE_DEFAULT_ALLOCATOR);
-
- ~rbtree();
-
- public:
- // properties
- const allocator_type& get_allocator() const EA_NOEXCEPT;
- allocator_type& get_allocator() EA_NOEXCEPT;
- void set_allocator(const allocator_type& allocator);
-
- const key_compare& key_comp() const { return get_compare(); }
- key_compare& key_comp() { return get_compare(); }
-
- this_type& operator=(const this_type& x);
- this_type& operator=(std::initializer_list<value_type> ilist);
- this_type& operator=(this_type&& x);
-
- void swap(this_type& x);
-
- public:
- // iterators
- iterator begin() EA_NOEXCEPT;
- const_iterator begin() const EA_NOEXCEPT;
- const_iterator cbegin() const EA_NOEXCEPT;
-
- iterator end() EA_NOEXCEPT;
- const_iterator end() const EA_NOEXCEPT;
- const_iterator cend() const EA_NOEXCEPT;
-
- reverse_iterator rbegin() EA_NOEXCEPT;
- const_reverse_iterator rbegin() const EA_NOEXCEPT;
- const_reverse_iterator crbegin() const EA_NOEXCEPT;
-
- reverse_iterator rend() EA_NOEXCEPT;
- const_reverse_iterator rend() const EA_NOEXCEPT;
- const_reverse_iterator crend() const EA_NOEXCEPT;
-
- public:
- bool empty() const EA_NOEXCEPT;
- size_type size() const EA_NOEXCEPT;
-
- template <class... Args>
- insert_return_type emplace(Args&&... args);
-
- template <class... Args>
- iterator emplace_hint(const_iterator position, Args&&... args);
-
- // Standard conversion overload to avoid the overhead of mismatched 'pair<const Key, Value>' types.
- template <class P, class = typename eastl::enable_if<eastl::is_constructible<value_type, P&&>::value>::type>
- insert_return_type insert(P&& otherValue);
-
- // Currently limited to value_type instead of P because it collides with insert(InputIterator, InputIterator).
- // To allow this to work with templated P we need to implement a compile-time specialization for the
- // case that P&& is const_iterator and have that specialization handle insert(InputIterator, InputIterator)
- // instead of insert(InputIterator, InputIterator). Curiously, neither libstdc++ nor libc++
- // implement this function either, which suggests they ran into the same problem I did here
- // and haven't yet resolved it (at least as of March 2014, GCC 4.8.1).
- iterator insert(const_iterator hint, value_type&& value);
-
- /// map::insert and set::insert return a pair, while multimap::insert and
- /// multiset::insert return an iterator.
- insert_return_type insert(const value_type& value);
-
- // C++ standard: inserts value if and only if there is no element with
- // key equivalent to the key of t in containers with unique keys; always
- // inserts value in containers with equivalent keys. Always returns the
- // iterator pointing to the element with key equivalent to the key of value.
- // iterator position is a hint pointing to where the insert should start
- // to search. However, there is a potential defect/improvement report on this behaviour:
- // LWG issue #233 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1780.html)
- // We follow the same approach as SGI STL/STLPort and use the position as
- // a forced insertion position for the value when possible.
- iterator insert(const_iterator position, const value_type& value);
-
- void insert(std::initializer_list<value_type> ilist);
-
- template <typename InputIterator>
- void insert(InputIterator first, InputIterator last);
-
- // TODO(rparolin):
- // insert_return_type insert(node_type&& nh);
- // iterator insert(const_iterator hint, node_type&& nh);
-
- template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
- template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
- template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
- template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
-
- iterator erase(const_iterator position);
- iterator erase(const_iterator first, const_iterator last);
- reverse_iterator erase(const_reverse_iterator position);
- reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last);
-
- // For some reason, multiple STL versions make a specialization
- // for erasing an array of key_types. I'm pretty sure we don't
- // need this, but just to be safe we will follow suit.
- // The implementation is trivial. Returns void because the values
- // could well be randomly distributed throughout the tree and thus
- // a return value would be nearly meaningless.
- void erase(const key_type* first, const key_type* last);
-
- void clear();
- void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
-
- iterator find(const key_type& key);
- const_iterator find(const key_type& key) const;
-
- /// Implements a find whereby the user supplies a comparison of a different type
- /// than the tree's value_type. A useful case of this is one whereby you have
- /// a container of string objects but want to do searches via passing in char pointers.
- /// The problem is that without this kind of find, you need to do the expensive operation
- /// of converting the char pointer to a string so it can be used as the argument to the
- /// find function.
- ///
- /// Example usage (note that the compare uses string as first type and char* as second):
- /// set<string> strings;
- /// strings.find_as("hello", less_2<string, const char*>());
- ///
- template <typename U, typename Compare2> iterator find_as(const U& u, Compare2 compare2);
- template <typename U, typename Compare2> const_iterator find_as(const U& u, Compare2 compare2) const;
-
- iterator lower_bound(const key_type& key);
- const_iterator lower_bound(const key_type& key) const;
-
- iterator upper_bound(const key_type& key);
- const_iterator upper_bound(const key_type& key) const;
-
- bool validate() const;
- int validate_iterator(const_iterator i) const;
-
- protected:
- node_type* DoAllocateNode();
- void DoFreeNode(node_type* pNode);
-
- node_type* DoCreateNodeFromKey(const key_type& key);
-
- template<class... Args>
- node_type* DoCreateNode(Args&&... args);
- node_type* DoCreateNode(const value_type& value);
- node_type* DoCreateNode(value_type&& value);
- node_type* DoCreateNode(const node_type* pNodeSource, node_type* pNodeParent);
-
- node_type* DoCopySubtree(const node_type* pNodeSource, node_type* pNodeDest);
- void DoNukeSubtree(node_type* pNode);
-
- template <class... Args>
- eastl::pair<iterator, bool> DoInsertValue(true_type, Args&&... args);
-
- template <class... Args>
- iterator DoInsertValue(false_type, Args&&... args);
-
- eastl::pair<iterator, bool> DoInsertValue(true_type, value_type&& value);
- iterator DoInsertValue(false_type, value_type&& value);
-
- template <class... Args>
- iterator DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args);
- iterator DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, node_type* pNodeNew);
-
- eastl::pair<iterator, bool> DoInsertKey(true_type, const key_type& key);
- iterator DoInsertKey(false_type, const key_type& key);
-
- template <class... Args>
- iterator DoInsertValueHint(true_type, const_iterator position, Args&&... args);
-
- template <class... Args>
- iterator DoInsertValueHint(false_type, const_iterator position, Args&&... args);
-
- iterator DoInsertValueHint(true_type, const_iterator position, value_type&& value);
- iterator DoInsertValueHint(false_type, const_iterator position, value_type&& value);
-
- iterator DoInsertKey(true_type, const_iterator position, const key_type& key); // By design we return iterator and not a pair.
- iterator DoInsertKey(false_type, const_iterator position, const key_type& key);
- iterator DoInsertKeyImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key);
-
- node_type* DoGetKeyInsertionPositionUniqueKeys(bool& canInsert, const key_type& key);
- node_type* DoGetKeyInsertionPositionNonuniqueKeys(const key_type& key);
-
- node_type* DoGetKeyInsertionPositionUniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key);
- node_type* DoGetKeyInsertionPositionNonuniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key);
-
- }; // rbtree
-
-
-
-
-
- ///////////////////////////////////////////////////////////////////////
- // rbtree_node_base functions
- ///////////////////////////////////////////////////////////////////////
-
- EASTL_API inline rbtree_node_base* RBTreeGetMinChild(const rbtree_node_base* pNodeBase)
- {
- while(pNodeBase->mpNodeLeft)
- pNodeBase = pNodeBase->mpNodeLeft;
- return const_cast<rbtree_node_base*>(pNodeBase);
- }
-
- EASTL_API inline rbtree_node_base* RBTreeGetMaxChild(const rbtree_node_base* pNodeBase)
- {
- while(pNodeBase->mpNodeRight)
- pNodeBase = pNodeBase->mpNodeRight;
- return const_cast<rbtree_node_base*>(pNodeBase);
- }
-
- // The rest of the functions are non-trivial and are found in
- // the corresponding .cpp file to this file.
-
-
-
- ///////////////////////////////////////////////////////////////////////
- // rbtree_iterator functions
- ///////////////////////////////////////////////////////////////////////
-
- template <typename T, typename Pointer, typename Reference>
- rbtree_iterator<T, Pointer, Reference>::rbtree_iterator()
- : mpNode(NULL) { }
-
-
- template <typename T, typename Pointer, typename Reference>
- rbtree_iterator<T, Pointer, Reference>::rbtree_iterator(const node_type* pNode)
- : mpNode(static_cast<node_type*>(const_cast<node_type*>(pNode))) { }
-
-
- template <typename T, typename Pointer, typename Reference>
- rbtree_iterator<T, Pointer, Reference>::rbtree_iterator(const iterator& x)
- : mpNode(x.mpNode) { }
-
- template <typename T, typename Pointer, typename Reference>
- typename rbtree_iterator<T, Pointer, Reference>::this_type&
- rbtree_iterator<T, Pointer, Reference>::operator=(const iterator& x)
- {
- mpNode = x.mpNode;
- return *this;
- }
-
- template <typename T, typename Pointer, typename Reference>
- typename rbtree_iterator<T, Pointer, Reference>::reference
- rbtree_iterator<T, Pointer, Reference>::operator*() const
- { return mpNode->mValue; }
-
-
- template <typename T, typename Pointer, typename Reference>
- typename rbtree_iterator<T, Pointer, Reference>::pointer
- rbtree_iterator<T, Pointer, Reference>::operator->() const
- { return &mpNode->mValue; }
-
-
- template <typename T, typename Pointer, typename Reference>
- typename rbtree_iterator<T, Pointer, Reference>::this_type&
- rbtree_iterator<T, Pointer, Reference>::operator++()
- {
- mpNode = static_cast<node_type*>(RBTreeIncrement(mpNode));
- return *this;
- }
-
-
- template <typename T, typename Pointer, typename Reference>
- typename rbtree_iterator<T, Pointer, Reference>::this_type
- rbtree_iterator<T, Pointer, Reference>::operator++(int)
- {
- this_type temp(*this);
- mpNode = static_cast<node_type*>(RBTreeIncrement(mpNode));
- return temp;
- }
-
-
- template <typename T, typename Pointer, typename Reference>
- typename rbtree_iterator<T, Pointer, Reference>::this_type&
- rbtree_iterator<T, Pointer, Reference>::operator--()
- {
- mpNode = static_cast<node_type*>(RBTreeDecrement(mpNode));
- return *this;
- }
-
-
- template <typename T, typename Pointer, typename Reference>
- typename rbtree_iterator<T, Pointer, Reference>::this_type
- rbtree_iterator<T, Pointer, Reference>::operator--(int)
- {
- this_type temp(*this);
- mpNode = static_cast<node_type*>(RBTreeDecrement(mpNode));
- return temp;
- }
-
-
- // The C++ defect report #179 requires that we support comparisons between const and non-const iterators.
- // Thus we provide additional template paremeters here to support this. The defect report does not
- // require us to support comparisons between reverse_iterators and const_reverse_iterators.
- template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
- inline bool operator==(const rbtree_iterator<T, PointerA, ReferenceA>& a,
- const rbtree_iterator<T, PointerB, ReferenceB>& b)
- {
- return a.mpNode == b.mpNode;
- }
-
-
- template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
- inline bool operator!=(const rbtree_iterator<T, PointerA, ReferenceA>& a,
- const rbtree_iterator<T, PointerB, ReferenceB>& b)
- {
- return a.mpNode != b.mpNode;
- }
-
-
- // We provide a version of operator!= for the case where the iterators are of the
- // same type. This helps prevent ambiguity errors in the presence of rel_ops.
- template <typename T, typename Pointer, typename Reference>
- inline bool operator!=(const rbtree_iterator<T, Pointer, Reference>& a,
- const rbtree_iterator<T, Pointer, Reference>& b)
- {
- return a.mpNode != b.mpNode;
- }
-
-
-
-
- ///////////////////////////////////////////////////////////////////////
- // rbtree functions
- ///////////////////////////////////////////////////////////////////////
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline rbtree<K, V, C, A, E, bM, bU>::rbtree()
- : mAnchor(),
- mnSize(0),
- mAllocator(EASTL_RBTREE_DEFAULT_NAME)
- {
- reset_lose_memory();
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline rbtree<K, V, C, A, E, bM, bU>::rbtree(const allocator_type& allocator)
- : mAnchor(),
- mnSize(0),
- mAllocator(allocator)
- {
- reset_lose_memory();
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline rbtree<K, V, C, A, E, bM, bU>::rbtree(const C& compare, const allocator_type& allocator)
- : base_type(compare),
- mAnchor(),
- mnSize(0),
- mAllocator(allocator)
- {
- reset_lose_memory();
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline rbtree<K, V, C, A, E, bM, bU>::rbtree(const this_type& x)
- : base_type(x.get_compare()),
- mAnchor(),
- mnSize(0),
- mAllocator(x.mAllocator)
- {
- reset_lose_memory();
-
- if(x.mAnchor.mpNodeParent) // mAnchor.mpNodeParent is the rb_tree root node.
- {
- mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, (node_type*)&mAnchor);
- mAnchor.mpNodeRight = RBTreeGetMaxChild(mAnchor.mpNodeParent);
- mAnchor.mpNodeLeft = RBTreeGetMinChild(mAnchor.mpNodeParent);
- mnSize = x.mnSize;
- }
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline rbtree<K, V, C, A, E, bM, bU>::rbtree(this_type&& x)
- : base_type(x.get_compare()),
- mAnchor(),
- mnSize(0),
- mAllocator(x.mAllocator)
- {
- reset_lose_memory();
- swap(x);
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline rbtree<K, V, C, A, E, bM, bU>::rbtree(this_type&& x, const allocator_type& allocator)
- : base_type(x.get_compare()),
- mAnchor(),
- mnSize(0),
- mAllocator(allocator)
- {
- reset_lose_memory();
- swap(x); // swap will directly or indirectly handle the possibility that mAllocator != x.mAllocator.
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <typename InputIterator>
- inline rbtree<K, V, C, A, E, bM, bU>::rbtree(InputIterator first, InputIterator last, const C& compare, const allocator_type& allocator)
- : base_type(compare),
- mAnchor(),
- mnSize(0),
- mAllocator(allocator)
- {
- reset_lose_memory();
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- for(; first != last; ++first)
- insert(*first);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- clear();
- throw;
- }
- #endif
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline rbtree<K, V, C, A, E, bM, bU>::~rbtree()
- {
- // Erase the entire tree. DoNukeSubtree is not a
- // conventional erase function, as it does no rebalancing.
- DoNukeSubtree((node_type*)mAnchor.mpNodeParent);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline const typename rbtree<K, V, C, A, E, bM, bU>::allocator_type&
- rbtree<K, V, C, A, E, bM, bU>::get_allocator() const EA_NOEXCEPT
- {
- return mAllocator;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::allocator_type&
- rbtree<K, V, C, A, E, bM, bU>::get_allocator() EA_NOEXCEPT
- {
- return mAllocator;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline void rbtree<K, V, C, A, E, bM, bU>::set_allocator(const allocator_type& allocator)
- {
- mAllocator = allocator;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::size_type
- rbtree<K, V, C, A, E, bM, bU>::size() const EA_NOEXCEPT
- { return mnSize; }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline bool rbtree<K, V, C, A, E, bM, bU>::empty() const EA_NOEXCEPT
- { return (mnSize == 0); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::begin() EA_NOEXCEPT
- { return iterator(static_cast<node_type*>(mAnchor.mpNodeLeft)); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::begin() const EA_NOEXCEPT
- { return const_iterator(static_cast<node_type*>(const_cast<rbtree_node_base*>(mAnchor.mpNodeLeft))); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::cbegin() const EA_NOEXCEPT
- { return const_iterator(static_cast<node_type*>(const_cast<rbtree_node_base*>(mAnchor.mpNodeLeft))); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::end() EA_NOEXCEPT
- { return iterator(static_cast<node_type*>(&mAnchor)); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::end() const EA_NOEXCEPT
- { return const_iterator(static_cast<node_type*>(const_cast<rbtree_node_base*>(&mAnchor))); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::cend() const EA_NOEXCEPT
- { return const_iterator(static_cast<node_type*>(const_cast<rbtree_node_base*>(&mAnchor))); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::rbegin() EA_NOEXCEPT
- { return reverse_iterator(end()); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::rbegin() const EA_NOEXCEPT
- { return const_reverse_iterator(end()); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::crbegin() const EA_NOEXCEPT
- { return const_reverse_iterator(end()); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::rend() EA_NOEXCEPT
- { return reverse_iterator(begin()); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::rend() const EA_NOEXCEPT
- { return const_reverse_iterator(begin()); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::crend() const EA_NOEXCEPT
- { return const_reverse_iterator(begin()); }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::this_type&
- rbtree<K, V, C, A, E, bM, bU>::operator=(const this_type& x)
- {
- if(this != &x)
- {
- clear();
-
- #if EASTL_ALLOCATOR_COPY_ENABLED
- mAllocator = x.mAllocator;
- #endif
-
- get_compare() = x.get_compare();
-
- if(x.mAnchor.mpNodeParent) // mAnchor.mpNodeParent is the rb_tree root node.
- {
- mAnchor.mpNodeParent = DoCopySubtree((const node_type*)x.mAnchor.mpNodeParent, (node_type*)&mAnchor);
- mAnchor.mpNodeRight = RBTreeGetMaxChild(mAnchor.mpNodeParent);
- mAnchor.mpNodeLeft = RBTreeGetMinChild(mAnchor.mpNodeParent);
- mnSize = x.mnSize;
- }
- }
- return *this;
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::this_type&
- rbtree<K, V, C, A, E, bM, bU>::operator=(this_type&& x)
- {
- if(this != &x)
- {
- clear(); // To consider: Are we really required to clear here? x is going away soon and will clear itself in its dtor.
- swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy.
- }
- return *this;
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::this_type&
- rbtree<K, V, C, A, E, bM, bU>::operator=(std::initializer_list<value_type> ilist)
- {
- // The simplest means of doing this is to clear and insert. There probably isn't a generic
- // solution that's any more efficient without having prior knowledge of the ilist contents.
- clear();
-
- for(typename std::initializer_list<value_type>::iterator it = ilist.begin(), itEnd = ilist.end(); it != itEnd; ++it)
- DoInsertValue(has_unique_keys_type(), eastl::move(*it));
-
- return *this;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- void rbtree<K, V, C, A, E, bM, bU>::swap(this_type& x)
- {
- #if EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
- if(mAllocator == x.mAllocator) // If allocators are equivalent...
- #endif
- {
- // Most of our members can be exchaged by a basic swap:
- // We leave mAllocator as-is.
- eastl::swap(mnSize, x.mnSize);
- eastl::swap(get_compare(), x.get_compare());
- #if !EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
- eastl::swap(mAllocator, x.mAllocator);
- #endif
-
-
- // However, because our anchor node is a part of our class instance and not
- // dynamically allocated, we can't do a swap of it but must do a more elaborate
- // procedure. This is the downside to having the mAnchor be like this, but
- // otherwise we consider it a good idea to avoid allocating memory for a
- // nominal container instance.
-
- // We optimize for the expected most common case: both pointers being non-null.
- if(mAnchor.mpNodeParent && x.mAnchor.mpNodeParent) // If both pointers are non-null...
- {
- eastl::swap(mAnchor.mpNodeRight, x.mAnchor.mpNodeRight);
- eastl::swap(mAnchor.mpNodeLeft, x.mAnchor.mpNodeLeft);
- eastl::swap(mAnchor.mpNodeParent, x.mAnchor.mpNodeParent);
-
- // We need to fix up the anchors to point to themselves (we can't just swap them).
- mAnchor.mpNodeParent->mpNodeParent = &mAnchor;
- x.mAnchor.mpNodeParent->mpNodeParent = &x.mAnchor;
- }
- else if(mAnchor.mpNodeParent)
- {
- x.mAnchor.mpNodeRight = mAnchor.mpNodeRight;
- x.mAnchor.mpNodeLeft = mAnchor.mpNodeLeft;
- x.mAnchor.mpNodeParent = mAnchor.mpNodeParent;
- x.mAnchor.mpNodeParent->mpNodeParent = &x.mAnchor;
-
- // We need to fix up our anchor to point it itself (we can't have it swap with x).
- mAnchor.mpNodeRight = &mAnchor;
- mAnchor.mpNodeLeft = &mAnchor;
- mAnchor.mpNodeParent = NULL;
- }
- else if(x.mAnchor.mpNodeParent)
- {
- mAnchor.mpNodeRight = x.mAnchor.mpNodeRight;
- mAnchor.mpNodeLeft = x.mAnchor.mpNodeLeft;
- mAnchor.mpNodeParent = x.mAnchor.mpNodeParent;
- mAnchor.mpNodeParent->mpNodeParent = &mAnchor;
-
- // We need to fix up x's anchor to point it itself (we can't have it swap with us).
- x.mAnchor.mpNodeRight = &x.mAnchor;
- x.mAnchor.mpNodeLeft = &x.mAnchor;
- x.mAnchor.mpNodeParent = NULL;
- } // Else both are NULL and there is nothing to do.
- }
- #if EASTL_RBTREE_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
- else
- {
- const this_type temp(*this); // Can't call eastl::swap because that would
- *this = x; // itself call this member swap function.
- x = temp;
- }
- #endif
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- inline typename rbtree<K, V, C, A, E, bM, bU>::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator.
- rbtree<K, V, C, A, E, bM, bU>::emplace(Args&&... args)
- {
- return DoInsertValue(has_unique_keys_type(), eastl::forward<Args>(args)...);
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::emplace_hint(const_iterator position, Args&&... args)
- {
- return DoInsertValueHint(has_unique_keys_type(), position, eastl::forward<Args>(args)...);
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class P, class>
- inline typename rbtree<K, V, C, A, E, bM, bU>::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator.
- rbtree<K, V, C, A, E, bM, bU>::insert(P&& otherValue)
- {
- // Need to use forward instead of move because P&& is a "universal reference" instead of an rvalue reference.
- return emplace(eastl::forward<P>(otherValue));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::insert(const_iterator position, value_type&& value)
- {
- return DoInsertValueHint(has_unique_keys_type(), position, eastl::move(value));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::insert_return_type // map/set::insert return a pair, multimap/multiset::iterator return an iterator.
- rbtree<K, V, C, A, E, bM, bU>::insert(const value_type& value)
- {
- return DoInsertValue(has_unique_keys_type(), value);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::insert(const_iterator position, const value_type& value)
- {
- return DoInsertValueHint(has_unique_keys_type(), position, value);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class M>
- eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::insert_or_assign(const key_type& k, M&& obj)
- {
- auto iter = find(k);
-
- if(iter == end())
- {
- return insert(value_type(piecewise_construct, eastl::forward_as_tuple(k), eastl::forward_as_tuple(eastl::forward<M>(obj))));
- }
- else
- {
- iter->second = eastl::forward<M>(obj);
- return {iter, false};
- }
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class M>
- eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::insert_or_assign(key_type&& k, M&& obj)
- {
- auto iter = find(k);
-
- if(iter == end())
- {
- return insert(value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(k)), eastl::forward_as_tuple(eastl::forward<M>(obj))));
- }
- else
- {
- iter->second = eastl::forward<M>(obj);
- return {iter, false};
- }
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class M>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::insert_or_assign(const_iterator hint, const key_type& k, M&& obj)
- {
- auto iter = find(k);
-
- if(iter == end())
- {
- return insert(hint, value_type(piecewise_construct, eastl::forward_as_tuple(k), eastl::forward_as_tuple(eastl::forward<M>(obj))));
- }
- else
- {
- iter->second = eastl::forward<M>(obj);
- return iter;
- }
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class M>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::insert_or_assign(const_iterator hint, key_type&& k, M&& obj)
- {
- auto iter = find(k);
-
- if(iter == end())
- {
- return insert(hint, value_type(piecewise_construct, eastl::forward_as_tuple(eastl::move(k)), eastl::forward_as_tuple(eastl::forward<M>(obj))));
- }
- else
- {
- iter->second = eastl::forward<M>(obj);
- return iter;
- }
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoGetKeyInsertionPositionUniqueKeys(bool& canInsert, const key_type& key)
- {
- // This code is essentially a slightly modified copy of the the rbtree::insert
- // function whereby this version takes a key and not a full value_type.
- extract_key extractKey;
-
- node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node.
- node_type* pLowerBound = (node_type*)&mAnchor; // Set it to the container end for now.
- node_type* pParent; // This will be where we insert the new node.
-
- bool bValueLessThanNode = true; // If the tree is empty, this will result in an insertion at the front.
-
- // Find insertion position of the value. This will either be a position which
- // already contains the value, a position which is greater than the value or
- // end(), which we treat like a position which is greater than the value.
- while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree.
- {
- bValueLessThanNode = compare(key, extractKey(pCurrent->mValue));
- pLowerBound = pCurrent;
-
- if(bValueLessThanNode)
- {
- EASTL_VALIDATE_COMPARE(!compare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane.
- pCurrent = (node_type*)pCurrent->mpNodeLeft;
- }
- else
- pCurrent = (node_type*)pCurrent->mpNodeRight;
- }
-
- pParent = pLowerBound; // pLowerBound is actually upper bound right now (i.e. it is > value instead of <=), but we will make it the lower bound below.
-
- if(bValueLessThanNode) // If we ended up on the left side of the last parent node...
- {
- if(EASTL_LIKELY(pLowerBound != (node_type*)mAnchor.mpNodeLeft)) // If the tree was empty or if we otherwise need to insert at the very front of the tree...
- {
- // At this point, pLowerBound points to a node which is > than value.
- // Move it back by one, so that it points to a node which is <= value.
- pLowerBound = (node_type*)RBTreeDecrement(pLowerBound);
- }
- else
- {
- canInsert = true;
- return pLowerBound;
- }
- }
-
- // Since here we require values to be unique, we will do nothing if the value already exists.
- if(compare(extractKey(pLowerBound->mValue), key)) // If the node is < the value (i.e. if value is >= the node)...
- {
- EASTL_VALIDATE_COMPARE(!compare(key, extractKey(pLowerBound->mValue))); // Validate that the compare function is sane.
- canInsert = true;
- return pParent;
- }
-
- // The item already exists (as found by the compare directly above), so return false.
- canInsert = false;
- return pLowerBound;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoGetKeyInsertionPositionNonuniqueKeys(const key_type& key)
- {
- // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set).
- node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node.
- node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now.
- extract_key extractKey;
-
- while(pCurrent)
- {
- pRangeEnd = pCurrent;
-
- if(compare(key, extractKey(pCurrent->mValue)))
- {
- EASTL_VALIDATE_COMPARE(!compare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane.
- pCurrent = (node_type*)pCurrent->mpNodeLeft;
- }
- else
- pCurrent = (node_type*)pCurrent->mpNodeRight;
- }
-
- return pRangeEnd;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValue(true_type, value_type&& value)
- {
- extract_key extractKey;
- key_type key(extractKey(value));
- bool canInsert;
- node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key);
-
- if(canInsert)
- {
- const iterator itResult(DoInsertValueImpl(pPosition, false, key, eastl::move(value)));
- return pair<iterator, bool>(itResult, true);
- }
-
- return pair<iterator, bool>(iterator(pPosition), false);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValue(false_type, value_type&& value)
- {
- extract_key extractKey;
- key_type key(extractKey(value));
- node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key);
-
- return DoInsertValueImpl(pPosition, false, key, eastl::move(value));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValue(true_type, Args&&... args) // true_type means keys are unique.
- {
- // This is the pathway for insertion of unique keys (map and set, but not multimap and multiset).
- // Note that we return a pair and not an iterator. This is because the C++ standard for map
- // and set is to return a pair and not just an iterator.
-
- node_type* pNodeNew = DoCreateNode(eastl::forward<Args>(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized.
- const key_type& key = extract_key{}(pNodeNew->mValue);
-
- bool canInsert;
- node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key);
-
- if(canInsert)
- {
- iterator itResult(DoInsertValueImpl(pPosition, false, key, pNodeNew));
- return pair<iterator, bool>(itResult, true);
- }
-
- DoFreeNode(pNodeNew);
- return pair<iterator, bool>(iterator(pPosition), false);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValue(false_type, Args&&... args) // false_type means keys are not unique.
- {
- // We have a problem here if sizeof(value_type) is too big for the stack. We may want to consider having a specialization for large value_types.
- // To do: Change this so that we call DoCreateNode(eastl::forward<Args>(args)...) here and use the value from the resulting pNode to get the
- // key, and make DoInsertValueImpl take that node as an argument. That way there is no value created on the stack.
-
- node_type* const pNodeNew = DoCreateNode(eastl::forward<Args>(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized.
- const key_type& key = extract_key{}(pNodeNew->mValue);
-
- node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key);
-
- return DoInsertValueImpl(pPosition, false, key, pNodeNew);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, Args&&... args)
- {
- node_type* const pNodeNew = DoCreateNode(eastl::forward<Args>(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized.
-
- return DoInsertValueImpl(pNodeParent, bForceToLeft, key, pNodeNew);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValueImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key, node_type* pNodeNew)
- {
- EASTL_ASSERT_MSG(pNodeNew != nullptr, "node to insert to the rbtree must not be null");
-
- RBTreeSide side;
- extract_key extractKey;
-
- // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal.
- // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report
- // suggests that we should use the insert hint position to force an ordering. So that's what we do.
- if(bForceToLeft || (pNodeParent == &mAnchor) || compare(key, extractKey(pNodeParent->mValue)))
- side = kRBTreeSideLeft;
- else
- side = kRBTreeSideRight;
-
- RBTreeInsert(pNodeNew, pNodeParent, &mAnchor, side);
- mnSize++;
-
- return iterator(pNodeNew);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- eastl::pair<typename rbtree<K, V, C, A, E, bM, bU>::iterator, bool>
- rbtree<K, V, C, A, E, bM, bU>::DoInsertKey(true_type, const key_type& key) // true_type means keys are unique.
- {
- // This is the pathway for insertion of unique keys (map and set, but not multimap and multiset).
- // Note that we return a pair and not an iterator. This is because the C++ standard for map
- // and set is to return a pair and not just an iterator.
- bool canInsert;
- node_type* pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key);
-
- if(canInsert)
- {
- const iterator itResult(DoInsertKeyImpl(pPosition, false, key));
- return pair<iterator, bool>(itResult, true);
- }
-
- return pair<iterator, bool>(iterator(pPosition), false);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertKey(false_type, const key_type& key) // false_type means keys are not unique.
- {
- node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key);
-
- return DoInsertKeyImpl(pPosition, false, key);
- }
-
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoGetKeyInsertionPositionUniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key)
- {
- extract_key extractKey;
-
- if((position.mpNode != mAnchor.mpNodeRight) && (position.mpNode != &mAnchor)) // If the user specified a specific insertion position...
- {
- iterator itNext(position.mpNode);
- ++itNext;
-
- // To consider: Change this so that 'position' specifies the position after
- // where the insertion goes and not the position before where the insertion goes.
- // Doing so would make this more in line with user expectations and with LWG #233.
- const bool bPositionLessThanValue = compare(extractKey(position.mpNode->mValue), key);
-
- if(bPositionLessThanValue) // If (value > *position)...
- {
- EASTL_VALIDATE_COMPARE(!compare(key, extractKey(position.mpNode->mValue))); // Validate that the compare function is sane.
-
- const bool bValueLessThanNext = compare(key, extractKey(itNext.mpNode->mValue));
-
- if(bValueLessThanNext) // If value < *itNext...
- {
- EASTL_VALIDATE_COMPARE(!compare(extractKey(itNext.mpNode->mValue), key)); // Validate that the compare function is sane.
-
- if(position.mpNode->mpNodeRight)
- {
- bForceToLeft = true; // Specifically insert in front of (to the left of) itNext (and thus after 'position').
- return itNext.mpNode;
- }
-
- bForceToLeft = false;
- return position.mpNode;
- }
- }
-
- bForceToLeft = false;
- return NULL; // The above specified hint was not useful, then we do a regular insertion.
- }
-
- if(mnSize && compare(extractKey(((node_type*)mAnchor.mpNodeRight)->mValue), key))
- {
- EASTL_VALIDATE_COMPARE(!compare(key, extractKey(((node_type*)mAnchor.mpNodeRight)->mValue))); // Validate that the compare function is sane.
- bForceToLeft = false;
- return (node_type*)mAnchor.mpNodeRight;
- }
-
- bForceToLeft = false;
- return NULL; // The caller can do a default insert.
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoGetKeyInsertionPositionNonuniqueKeysHint(const_iterator position, bool& bForceToLeft, const key_type& key)
- {
- extract_key extractKey;
-
- if((position.mpNode != mAnchor.mpNodeRight) && (position.mpNode != &mAnchor)) // If the user specified a specific insertion position...
- {
- iterator itNext(position.mpNode);
- ++itNext;
-
- // To consider: Change this so that 'position' specifies the position after
- // where the insertion goes and not the position before where the insertion goes.
- // Doing so would make this more in line with user expectations and with LWG #233.
- if(!compare(key, extractKey(position.mpNode->mValue)) && // If value >= *position &&
- !compare(extractKey(itNext.mpNode->mValue), key)) // if value <= *itNext...
- {
- if(position.mpNode->mpNodeRight) // If there are any nodes to the right... [this expression will always be true as long as we aren't at the end()]
- {
- bForceToLeft = true; // Specifically insert in front of (to the left of) itNext (and thus after 'position').
- return itNext.mpNode;
- }
-
- bForceToLeft = false;
- return position.mpNode;
- }
-
- bForceToLeft = false;
- return NULL; // The above specified hint was not useful, then we do a regular insertion.
- }
-
- // This pathway shouldn't be commonly executed, as the user shouldn't be calling
- // this hinted version of insert if the user isn't providing a useful hint.
- if(mnSize && !compare(key, extractKey(((node_type*)mAnchor.mpNodeRight)->mValue))) // If we are non-empty and the value is >= the last node...
- {
- bForceToLeft =false;
- return (node_type*)mAnchor.mpNodeRight;
- }
-
- bForceToLeft = false;
- return NULL;
- }
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValueHint(true_type, const_iterator position, Args&&... args) // true_type means keys are unique.
- {
- // This is the pathway for insertion of unique keys (map and set, but not multimap and multiset).
- //
- // We follow the same approach as SGI STL/STLPort and use the position as
- // a forced insertion position for the value when possible.
-
- node_type* pNodeNew = DoCreateNode(eastl::forward<Args>(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized.
- const key_type& key(extract_key{}(pNodeNew->mValue));
-
- bool bForceToLeft;
- node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key);
-
- if (!pPosition)
- {
- bool canInsert;
- pPosition = DoGetKeyInsertionPositionUniqueKeys(canInsert, key);
-
- if (!canInsert)
- {
- DoFreeNode(pNodeNew);
- return iterator(pPosition);
- }
-
- bForceToLeft = false;
- }
-
- return DoInsertValueImpl(pPosition, bForceToLeft, key, pNodeNew);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <class... Args>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValueHint(false_type, const_iterator position, Args&&... args) // false_type means keys are not unique.
- {
- // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set).
- //
- // We follow the same approach as SGI STL/STLPort and use the position as
- // a forced insertion position for the value when possible.
-
- node_type* pNodeNew = DoCreateNode(eastl::forward<Args>(args)...); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized.
- const key_type& key(extract_key{}(pNodeNew->mValue));
-
- bool bForceToLeft;
- node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key);
-
- if (!pPosition)
- {
- pPosition = DoGetKeyInsertionPositionNonuniqueKeys(key);
- bForceToLeft = false;
- }
-
- return DoInsertValueImpl(pPosition, bForceToLeft, key, pNodeNew);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValueHint(true_type, const_iterator position, value_type&& value) // true_type means keys are unique.
- {
- // This is the pathway for insertion of unique keys (map and set, but not multimap and multiset).
- //
- // We follow the same approach as SGI STL/STLPort and use the position as
- // a forced insertion position for the value when possible.
-
- extract_key extractKey;
- key_type key(extractKey(value));
- bool bForceToLeft;
- node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key);
-
- if(pPosition)
- return DoInsertValueImpl(pPosition, bForceToLeft, key, eastl::move(value));
- else
- return DoInsertValue(has_unique_keys_type(), eastl::move(value)).first;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertValueHint(false_type, const_iterator position, value_type&& value) // false_type means keys are not unique.
- {
- // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set).
- //
- // We follow the same approach as SGI STL/STLPort and use the position as
- // a forced insertion position for the value when possible.
- extract_key extractKey;
- key_type key(extractKey(value));
- bool bForceToLeft;
- node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key);
-
- if(pPosition)
- return DoInsertValueImpl(pPosition, bForceToLeft, key, eastl::move(value));
- else
- return DoInsertValue(has_unique_keys_type(), eastl::move(value));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertKey(true_type, const_iterator position, const key_type& key) // true_type means keys are unique.
- {
- bool bForceToLeft;
- node_type* pPosition = DoGetKeyInsertionPositionUniqueKeysHint(position, bForceToLeft, key);
-
- if(pPosition)
- return DoInsertKeyImpl(pPosition, bForceToLeft, key);
- else
- return DoInsertKey(has_unique_keys_type(), key).first;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertKey(false_type, const_iterator position, const key_type& key) // false_type means keys are not unique.
- {
- // This is the pathway for insertion of non-unique keys (multimap and multiset, but not map and set).
- //
- // We follow the same approach as SGI STL/STLPort and use the position as
- // a forced insertion position for the value when possible.
- bool bForceToLeft;
- node_type* pPosition = DoGetKeyInsertionPositionNonuniqueKeysHint(position, bForceToLeft, key);
-
- if(pPosition)
- return DoInsertKeyImpl(pPosition, bForceToLeft, key);
- else
- return DoInsertKey(has_unique_keys_type(), key); // We are empty or we are inserting at the end.
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::DoInsertKeyImpl(node_type* pNodeParent, bool bForceToLeft, const key_type& key)
- {
- RBTreeSide side;
- extract_key extractKey;
-
- // The reason we may want to have bForceToLeft == true is that pNodeParent->mValue and value may be equal.
- // In that case it doesn't matter what side we insert on, except that the C++ LWG #233 improvement report
- // suggests that we should use the insert hint position to force an ordering. So that's what we do.
- if(bForceToLeft || (pNodeParent == &mAnchor) || compare(key, extractKey(pNodeParent->mValue)))
- side = kRBTreeSideLeft;
- else
- side = kRBTreeSideRight;
-
- node_type* const pNodeNew = DoCreateNodeFromKey(key); // Note that pNodeNew->mpLeft, mpRight, mpParent, will be uninitialized.
- RBTreeInsert(pNodeNew, pNodeParent, &mAnchor, side);
- mnSize++;
-
- return iterator(pNodeNew);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- void rbtree<K, V, C, A, E, bM, bU>::insert(std::initializer_list<value_type> ilist)
- {
- for(typename std::initializer_list<value_type>::iterator it = ilist.begin(), itEnd = ilist.end(); it != itEnd; ++it)
- DoInsertValue(has_unique_keys_type(), eastl::move(*it));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <typename InputIterator>
- void rbtree<K, V, C, A, E, bM, bU>::insert(InputIterator first, InputIterator last)
- {
- for( ; first != last; ++first)
- DoInsertValue(has_unique_keys_type(), *first); // Or maybe we should call 'insert(end(), *first)' instead. If the first-last range was sorted then this might make some sense.
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline void rbtree<K, V, C, A, E, bM, bU>::clear()
- {
- // Erase the entire tree. DoNukeSubtree is not a
- // conventional erase function, as it does no rebalancing.
- DoNukeSubtree((node_type*)mAnchor.mpNodeParent);
- reset_lose_memory();
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline void rbtree<K, V, C, A, E, bM, bU>::reset_lose_memory()
- {
- // The reset_lose_memory function is a special extension function which unilaterally
- // resets the container to an empty state without freeing the memory of
- // the contained objects. This is useful for very quickly tearing down a
- // container built into scratch memory.
- mAnchor.mpNodeRight = &mAnchor;
- mAnchor.mpNodeLeft = &mAnchor;
- mAnchor.mpNodeParent = NULL;
- mAnchor.mColor = kRBTreeColorRed;
- mnSize = 0;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::erase(const_iterator position)
- {
- const iterator iErase(position.mpNode);
- --mnSize; // Interleave this between the two references to itNext. We expect no exceptions to occur during the code below.
- ++position;
- RBTreeErase(iErase.mpNode, &mAnchor);
- DoFreeNode(iErase.mpNode);
- return iterator(position.mpNode);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::erase(const_iterator first, const_iterator last)
- {
- // We expect that if the user means to clear the container, they will call clear.
- if(EASTL_LIKELY((first.mpNode != mAnchor.mpNodeLeft) || (last.mpNode != &mAnchor))) // If (first != begin or last != end) ...
- {
- // Basic implementation:
- while(first != last)
- first = erase(first);
- return iterator(first.mpNode);
-
- // Inlined implementation:
- //size_type n = 0;
- //while(first != last)
- //{
- // const iterator itErase(first);
- // ++n;
- // ++first;
- // RBTreeErase(itErase.mpNode, &mAnchor);
- // DoFreeNode(itErase.mpNode);
- //}
- //mnSize -= n;
- //return first;
- }
-
- clear();
- return iterator((node_type*)&mAnchor); // Same as: return end();
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::erase(const_reverse_iterator position)
- {
- return reverse_iterator(erase((++position).base()));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::reverse_iterator
- rbtree<K, V, C, A, E, bM, bU>::erase(const_reverse_iterator first, const_reverse_iterator last)
- {
- // Version which erases in order from first to last.
- // difference_type i(first.base() - last.base());
- // while(i--)
- // first = erase(first);
- // return first;
-
- // Version which erases in order from last to first, but is slightly more efficient:
- return reverse_iterator(erase((++last).base(), (++first).base()));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline void rbtree<K, V, C, A, E, bM, bU>::erase(const key_type* first, const key_type* last)
- {
- // We have no choice but to run a loop like this, as the first/last range could
- // have values that are discontiguously located in the tree. And some may not
- // even be in the tree.
- while(first != last)
- erase(*first++);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::find(const key_type& key)
- {
- // To consider: Implement this instead via calling lower_bound and
- // inspecting the result. The following is an implementation of this:
- // const iterator it(lower_bound(key));
- // return ((it.mpNode == &mAnchor) || compare(key, extractKey(it.mpNode->mValue))) ? iterator(&mAnchor) : it;
- // We don't currently implement the above because in practice people tend to call
- // find a lot with trees, but very uncommonly call lower_bound.
- extract_key extractKey;
-
- node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node.
- node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now.
-
- while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree.
- {
- if(EASTL_LIKELY(!compare(extractKey(pCurrent->mValue), key))) // If pCurrent is >= key...
- {
- pRangeEnd = pCurrent;
- pCurrent = (node_type*)pCurrent->mpNodeLeft;
- }
- else
- {
- EASTL_VALIDATE_COMPARE(!compare(key, extractKey(pCurrent->mValue))); // Validate that the compare function is sane.
- pCurrent = (node_type*)pCurrent->mpNodeRight;
- }
- }
-
- if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !compare(key, extractKey(pRangeEnd->mValue))))
- return iterator(pRangeEnd);
- return iterator((node_type*)&mAnchor);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::find(const key_type& key) const
- {
- typedef rbtree<K, V, C, A, E, bM, bU> rbtree_type;
- return const_iterator(const_cast<rbtree_type*>(this)->find(key));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <typename U, typename Compare2>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::find_as(const U& u, Compare2 compare2)
- {
- extract_key extractKey;
-
- node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node.
- node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now.
-
- while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree.
- {
- if(EASTL_LIKELY(!compare2(extractKey(pCurrent->mValue), u))) // If pCurrent is >= u...
- {
- pRangeEnd = pCurrent;
- pCurrent = (node_type*)pCurrent->mpNodeLeft;
- }
- else
- {
- EASTL_VALIDATE_COMPARE(!compare2(u, extractKey(pCurrent->mValue))); // Validate that the compare function is sane.
- pCurrent = (node_type*)pCurrent->mpNodeRight;
- }
- }
-
- if(EASTL_LIKELY((pRangeEnd != &mAnchor) && !compare2(u, extractKey(pRangeEnd->mValue))))
- return iterator(pRangeEnd);
- return iterator((node_type*)&mAnchor);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template <typename U, typename Compare2>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::find_as(const U& u, Compare2 compare2) const
- {
- typedef rbtree<K, V, C, A, E, bM, bU> rbtree_type;
- return const_iterator(const_cast<rbtree_type*>(this)->find_as(u, compare2));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::lower_bound(const key_type& key)
- {
- extract_key extractKey;
-
- node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node.
- node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now.
-
- while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree.
- {
- if(EASTL_LIKELY(!compare(extractKey(pCurrent->mValue), key))) // If pCurrent is >= key...
- {
- pRangeEnd = pCurrent;
- pCurrent = (node_type*)pCurrent->mpNodeLeft;
- }
- else
- {
- EASTL_VALIDATE_COMPARE(!compare(key, extractKey(pCurrent->mValue))); // Validate that the compare function is sane.
- pCurrent = (node_type*)pCurrent->mpNodeRight;
- }
- }
-
- return iterator(pRangeEnd);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::lower_bound(const key_type& key) const
- {
- typedef rbtree<K, V, C, A, E, bM, bU> rbtree_type;
- return const_iterator(const_cast<rbtree_type*>(this)->lower_bound(key));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::iterator
- rbtree<K, V, C, A, E, bM, bU>::upper_bound(const key_type& key)
- {
- extract_key extractKey;
-
- node_type* pCurrent = (node_type*)mAnchor.mpNodeParent; // Start with the root node.
- node_type* pRangeEnd = (node_type*)&mAnchor; // Set it to the container end for now.
-
- while(EASTL_LIKELY(pCurrent)) // Do a walk down the tree.
- {
- if(EASTL_LIKELY(compare(key, extractKey(pCurrent->mValue)))) // If key is < pCurrent...
- {
- EASTL_VALIDATE_COMPARE(!compare(extractKey(pCurrent->mValue), key)); // Validate that the compare function is sane.
- pRangeEnd = pCurrent;
- pCurrent = (node_type*)pCurrent->mpNodeLeft;
- }
- else
- pCurrent = (node_type*)pCurrent->mpNodeRight;
- }
-
- return iterator(pRangeEnd);
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::const_iterator
- rbtree<K, V, C, A, E, bM, bU>::upper_bound(const key_type& key) const
- {
- typedef rbtree<K, V, C, A, E, bM, bU> rbtree_type;
- return const_iterator(const_cast<rbtree_type*>(this)->upper_bound(key));
- }
-
-
- // To do: Move this validate function entirely to a template-less implementation.
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- bool rbtree<K, V, C, A, E, bM, bU>::validate() const
- {
- // Red-black trees have the following canonical properties which we validate here:
- // 1 Every node is either red or black.
- // 2 Every leaf (NULL) is black by defintion. Any number of black nodes may appear in a sequence.
- // 3 If a node is red, then both its children are black. Thus, on any path from
- // the root to a leaf, red nodes must not be adjacent.
- // 4 Every simple path from a node to a descendant leaf contains the same number of black nodes.
- // 5 The mnSize member of the tree must equal the number of nodes in the tree.
- // 6 The tree is sorted as per a conventional binary tree.
- // 7 The comparison function is sane; it obeys strict weak ordering. If compare(a,b) is true, then compare(b,a) must be false. Both cannot be true.
-
- extract_key extractKey;
-
- if(mnSize)
- {
- // Verify basic integrity.
- //if(!mAnchor.mpNodeParent || (mAnchor.mpNodeLeft == mAnchor.mpNodeRight))
- // return false; // Fix this for case of empty tree.
-
- if(mAnchor.mpNodeLeft != RBTreeGetMinChild(mAnchor.mpNodeParent))
- return false;
-
- if(mAnchor.mpNodeRight != RBTreeGetMaxChild(mAnchor.mpNodeParent))
- return false;
-
- const size_t nBlackCount = RBTreeGetBlackCount(mAnchor.mpNodeParent, mAnchor.mpNodeLeft);
- size_type nIteratedSize = 0;
-
- for(const_iterator it = begin(); it != end(); ++it, ++nIteratedSize)
- {
- const node_type* const pNode = (const node_type*)it.mpNode;
- const node_type* const pNodeRight = (const node_type*)pNode->mpNodeRight;
- const node_type* const pNodeLeft = (const node_type*)pNode->mpNodeLeft;
-
- // Verify #7 above.
- if(pNodeRight && compare(extractKey(pNodeRight->mValue), extractKey(pNode->mValue)) && compare(extractKey(pNode->mValue), extractKey(pNodeRight->mValue))) // Validate that the compare function is sane.
- return false;
-
- // Verify #7 above.
- if(pNodeLeft && compare(extractKey(pNodeLeft->mValue), extractKey(pNode->mValue)) && compare(extractKey(pNode->mValue), extractKey(pNodeLeft->mValue))) // Validate that the compare function is sane.
- return false;
-
- // Verify item #1 above.
- if((pNode->mColor != kRBTreeColorRed) && (pNode->mColor != kRBTreeColorBlack))
- return false;
-
- // Verify item #3 above.
- if(pNode->mColor == kRBTreeColorRed)
- {
- if((pNodeRight && (pNodeRight->mColor == kRBTreeColorRed)) ||
- (pNodeLeft && (pNodeLeft->mColor == kRBTreeColorRed)))
- return false;
- }
-
- // Verify item #6 above.
- if(pNodeRight && compare(extractKey(pNodeRight->mValue), extractKey(pNode->mValue)))
- return false;
-
- if(pNodeLeft && compare(extractKey(pNode->mValue), extractKey(pNodeLeft->mValue)))
- return false;
-
- if(!pNodeRight && !pNodeLeft) // If we are at a bottom node of the tree...
- {
- // Verify item #4 above.
- if(RBTreeGetBlackCount(mAnchor.mpNodeParent, pNode) != nBlackCount)
- return false;
- }
- }
-
- // Verify item #5 above.
- if(nIteratedSize != mnSize)
- return false;
-
- return true;
- }
- else
- {
- if((mAnchor.mpNodeLeft != &mAnchor) || (mAnchor.mpNodeRight != &mAnchor))
- return false;
- }
-
- return true;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline int rbtree<K, V, C, A, E, bM, bU>::validate_iterator(const_iterator i) const
- {
- // To do: Come up with a more efficient mechanism of doing this.
-
- for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp)
- {
- if(temp == i)
- return (isf_valid | isf_current | isf_can_dereference);
- }
-
- if(i == end())
- return (isf_valid | isf_current);
-
- return isf_none;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoAllocateNode()
- {
- auto* pNode = (node_type*)allocate_memory(mAllocator, sizeof(node_type), EASTL_ALIGN_OF(node_type), 0);
- EASTL_ASSERT_MSG(pNode != nullptr, "the behaviour of eastl::allocators that return nullptr is not defined.");
-
- return pNode;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- inline void rbtree<K, V, C, A, E, bM, bU>::DoFreeNode(node_type* pNode)
- {
- pNode->~node_type();
- EASTLFree(mAllocator, pNode, sizeof(node_type));
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoCreateNodeFromKey(const key_type& key)
- {
- // Note that this function intentionally leaves the node pointers uninitialized.
- // The caller would otherwise just turn right around and modify them, so there's
- // no point in us initializing them to anything (except in a debug build).
- node_type* const pNode = DoAllocateNode();
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- ::new (eastl::addressof(pNode->mValue)) value_type(pair_first_construct, key);
-
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- DoFreeNode(pNode);
- throw;
- }
- #endif
-
- #if EASTL_DEBUG
- pNode->mpNodeRight = NULL;
- pNode->mpNodeLeft = NULL;
- pNode->mpNodeParent = NULL;
- pNode->mColor = kRBTreeColorBlack;
- #endif
-
- return pNode;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoCreateNode(const value_type& value)
- {
- // Note that this function intentionally leaves the node pointers uninitialized.
- // The caller would otherwise just turn right around and modify them, so there's
- // no point in us initializing them to anything (except in a debug build).
- node_type* const pNode = DoAllocateNode();
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- ::new(eastl::addressof(pNode->mValue)) value_type(value);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- DoFreeNode(pNode);
- throw;
- }
- #endif
-
- #if EASTL_DEBUG
- pNode->mpNodeRight = NULL;
- pNode->mpNodeLeft = NULL;
- pNode->mpNodeParent = NULL;
- pNode->mColor = kRBTreeColorBlack;
- #endif
-
- return pNode;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoCreateNode(value_type&& value)
- {
- // Note that this function intentionally leaves the node pointers uninitialized.
- // The caller would otherwise just turn right around and modify them, so there's
- // no point in us initializing them to anything (except in a debug build).
- node_type* const pNode = DoAllocateNode();
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- ::new(eastl::addressof(pNode->mValue)) value_type(eastl::move(value));
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- DoFreeNode(pNode);
- throw;
- }
- #endif
-
- #if EASTL_DEBUG
- pNode->mpNodeRight = NULL;
- pNode->mpNodeLeft = NULL;
- pNode->mpNodeParent = NULL;
- pNode->mColor = kRBTreeColorBlack;
- #endif
-
- return pNode;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- template<class... Args>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoCreateNode(Args&&... args)
- {
- // Note that this function intentionally leaves the node pointers uninitialized.
- // The caller would otherwise just turn right around and modify them, so there's
- // no point in us initializing them to anything (except in a debug build).
- node_type* const pNode = DoAllocateNode();
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- ::new(eastl::addressof(pNode->mValue)) value_type(eastl::forward<Args>(args)...);
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- DoFreeNode(pNode);
- throw;
- }
- #endif
-
- #if EASTL_DEBUG
- pNode->mpNodeRight = NULL;
- pNode->mpNodeLeft = NULL;
- pNode->mpNodeParent = NULL;
- pNode->mColor = kRBTreeColorBlack;
- #endif
-
- return pNode;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoCreateNode(const node_type* pNodeSource, node_type* pNodeParent)
- {
- node_type* const pNode = DoCreateNode(pNodeSource->mValue);
-
- pNode->mpNodeRight = NULL;
- pNode->mpNodeLeft = NULL;
- pNode->mpNodeParent = pNodeParent;
- pNode->mColor = pNodeSource->mColor;
-
- return pNode;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- typename rbtree<K, V, C, A, E, bM, bU>::node_type*
- rbtree<K, V, C, A, E, bM, bU>::DoCopySubtree(const node_type* pNodeSource, node_type* pNodeDest)
- {
- node_type* const pNewNodeRoot = DoCreateNode(pNodeSource, pNodeDest);
-
- #if EASTL_EXCEPTIONS_ENABLED
- try
- {
- #endif
- // Copy the right side of the tree recursively.
- if(pNodeSource->mpNodeRight)
- pNewNodeRoot->mpNodeRight = DoCopySubtree((const node_type*)pNodeSource->mpNodeRight, pNewNodeRoot);
-
- node_type* pNewNodeLeft;
-
- for(pNodeSource = (node_type*)pNodeSource->mpNodeLeft, pNodeDest = pNewNodeRoot;
- pNodeSource;
- pNodeSource = (node_type*)pNodeSource->mpNodeLeft, pNodeDest = pNewNodeLeft)
- {
- pNewNodeLeft = DoCreateNode(pNodeSource, pNodeDest);
-
- pNodeDest->mpNodeLeft = pNewNodeLeft;
-
- // Copy the right side of the tree recursively.
- if(pNodeSource->mpNodeRight)
- pNewNodeLeft->mpNodeRight = DoCopySubtree((const node_type*)pNodeSource->mpNodeRight, pNewNodeLeft);
- }
- #if EASTL_EXCEPTIONS_ENABLED
- }
- catch(...)
- {
- DoNukeSubtree(pNewNodeRoot);
- throw;
- }
- #endif
-
- return pNewNodeRoot;
- }
-
-
- template <typename K, typename V, typename C, typename A, typename E, bool bM, bool bU>
- void rbtree<K, V, C, A, E, bM, bU>::DoNukeSubtree(node_type* pNode)
- {
- while(pNode) // Recursively traverse the tree and destroy items as we go.
- {
- DoNukeSubtree((node_type*)pNode->mpNodeRight);
-
- node_type* const pNodeLeft = (node_type*)pNode->mpNodeLeft;
- DoFreeNode(pNode);
- pNode = pNodeLeft;
- }
- }
-
-
-
- ///////////////////////////////////////////////////////////////////////
- // global operators
- ///////////////////////////////////////////////////////////////////////
-
- template <typename K, typename V, typename A, typename C, typename E, bool bM, bool bU>
- inline bool operator==(const rbtree<K, V, C, A, E, bM, bU>& a, const rbtree<K, V, C, A, E, bM, bU>& b)
- {
- return (a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin());
- }
-
-
- // Note that in operator< we do comparisons based on the tree value_type with operator<() of the
- // value_type instead of the tree's Compare function. For set/multiset, the value_type is T, while
- // for map/multimap the value_type is a pair<Key, T>. operator< for pair can be seen by looking
- // utility.h, but it basically is uses the operator< for pair.first and pair.second. The C++ standard
- // appears to require this behaviour, whether intentionally or not. If anything, a good reason to do
- // this is for consistency. A map and a vector that contain the same items should compare the same.
- template <typename K, typename V, typename A, typename C, typename E, bool bM, bool bU>
- inline bool operator<(const rbtree<K, V, C, A, E, bM, bU>& a, const rbtree<K, V, C, A, E, bM, bU>& b)
- {
- return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
- }
-
-
- template <typename K, typename V, typename A, typename C, typename E, bool bM, bool bU>
- inline bool operator!=(const rbtree<K, V, C, A, E, bM, bU>& a, const rbtree<K, V, C, A, E, bM, bU>& b)
- {
- return !(a == b);
- }
-
-
- template <typename K, typename V, typename A, typename C, typename E, bool bM, bool bU>
- inline bool operator>(const rbtree<K, V, C, A, E, bM, bU>& a, const rbtree<K, V, C, A, E, bM, bU>& b)
- {
- return b < a;
- }
-
-
- template <typename K, typename V, typename A, typename C, typename E, bool bM, bool bU>
- inline bool operator<=(const rbtree<K, V, C, A, E, bM, bU>& a, const rbtree<K, V, C, A, E, bM, bU>& b)
- {
- return !(b < a);
- }
-
-
- template <typename K, typename V, typename A, typename C, typename E, bool bM, bool bU>
- inline bool operator>=(const rbtree<K, V, C, A, E, bM, bU>& a, const rbtree<K, V, C, A, E, bM, bU>& b)
- {
- return !(a < b);
- }
-
-
- template <typename K, typename V, typename A, typename C, typename E, bool bM, bool bU>
- inline void swap(rbtree<K, V, C, A, E, bM, bU>& a, rbtree<K, V, C, A, E, bM, bU>& b)
- {
- a.swap(b);
- }
-
-
-} // namespace eastl
-
-
-EA_RESTORE_VC_WARNING();
-
-
-#endif // Header include guard