1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * A sorted tree with optimal access times, where recently-accessed elements
9 * are faster to access again.
12 #ifndef mozilla_SplayTree_h
13 #define mozilla_SplayTree_h
15 #include "mozilla/Assertions.h"
16 #include "mozilla/Attributes.h"
20 template <class T
, class C
>
26 template <class A
, class B
>
27 friend class SplayTree
;
29 SplayTreeNode() : mLeft(nullptr), mRight(nullptr), mParent(nullptr) {}
38 * Class which represents a splay tree.
39 * Splay trees are balanced binary search trees for which search, insert and
40 * remove are all amortized O(log n), but where accessing a node makes it
41 * faster to access that node in the future.
43 * T indicates the type of tree elements, Comparator must have a static
44 * compare(const T&, const T&) method ordering the elements. The compare
45 * method must be free from side effects.
47 template <typename T
, class Comparator
>
52 constexpr SplayTree() : mRoot(nullptr) {}
54 bool empty() const { return !mRoot
; }
56 T
* find(const T
& aValue
) {
61 T
* last
= lookup(aValue
);
63 return Comparator::compare(aValue
, *last
) == 0 ? last
: nullptr;
66 void insert(T
* aValue
) {
67 MOZ_ASSERT(!find(*aValue
), "Duplicate elements are not allowed.");
73 T
* last
= lookup(*aValue
);
74 int cmp
= Comparator::compare(*aValue
, *last
);
76 finishInsertion(last
, cmp
, aValue
);
79 T
* findOrInsert(const T
& aValue
);
81 T
* remove(const T
& aValue
) {
82 T
* last
= lookup(aValue
);
83 MOZ_ASSERT(last
, "This tree must contain the element being removed.");
84 MOZ_ASSERT(Comparator::compare(aValue
, *last
) == 0);
86 // Splay the tree so that the item to remove is the root.
88 MOZ_ASSERT(last
== mRoot
);
90 // Find another node which can be swapped in for the root: either the
91 // rightmost child of the root's left, or the leftmost child of the
97 while (swap
->mRight
) {
100 swapChild
= swap
->mLeft
;
101 } else if (mRoot
->mRight
) {
102 swap
= mRoot
->mRight
;
103 while (swap
->mLeft
) {
106 swapChild
= swap
->mRight
;
113 // The selected node has at most one child, in swapChild. Detach it
114 // from the subtree by replacing it with that child.
115 if (swap
== swap
->mParent
->mLeft
) {
116 swap
->mParent
->mLeft
= swapChild
;
118 swap
->mParent
->mRight
= swapChild
;
121 swapChild
->mParent
= swap
->mParent
;
124 // Make the selected node the new root.
126 mRoot
->mParent
= nullptr;
127 mRoot
->mLeft
= last
->mLeft
;
128 mRoot
->mRight
= last
->mRight
;
130 mRoot
->mLeft
->mParent
= mRoot
;
133 mRoot
->mRight
->mParent
= mRoot
;
136 last
->mLeft
= nullptr;
137 last
->mRight
= nullptr;
142 MOZ_ASSERT(mRoot
, "No min to remove!");
151 // For testing purposes only.
152 void checkCoherency() { checkCoherency(mRoot
, nullptr); }
156 * Returns the node in this comparing equal to |aValue|, or a node just
157 * greater or just less than |aValue| if there is no such node.
159 T
* lookup(const T
& aValue
) {
160 MOZ_ASSERT(!empty());
166 int c
= Comparator::compare(aValue
, *node
);
178 void finishInsertion(T
* aLast
, int32_t aCmp
, T
* aNew
) {
179 MOZ_ASSERT(aCmp
, "Nodes shouldn't be equal!");
181 T
** parentPointer
= (aCmp
< 0) ? &aLast
->mLeft
: &aLast
->mRight
;
182 MOZ_ASSERT(!*parentPointer
);
183 *parentPointer
= aNew
;
184 aNew
->mParent
= aLast
;
190 * Rotate the tree until |node| is at the root of the tree. Performing
191 * the rotations in this fashion preserves the amortized balancing of
194 void splay(T
* aNode
) {
197 while (aNode
!= mRoot
) {
198 T
* parent
= aNode
->mParent
;
199 if (parent
== mRoot
) {
202 MOZ_ASSERT(aNode
== mRoot
);
205 T
* grandparent
= parent
->mParent
;
206 if ((parent
->mLeft
== aNode
) == (grandparent
->mLeft
== parent
)) {
218 void rotate(T
* aNode
) {
219 // Rearrange nodes so that aNode becomes the parent of its current
220 // parent, while preserving the sortedness of the tree.
221 T
* parent
= aNode
->mParent
;
222 if (parent
->mLeft
== aNode
) {
226 parent
->mLeft
= aNode
->mRight
;
228 aNode
->mRight
->mParent
= parent
;
230 aNode
->mRight
= parent
;
232 MOZ_ASSERT(parent
->mRight
== aNode
);
236 parent
->mRight
= aNode
->mLeft
;
238 aNode
->mLeft
->mParent
= parent
;
240 aNode
->mLeft
= parent
;
242 aNode
->mParent
= parent
->mParent
;
243 parent
->mParent
= aNode
;
244 if (T
* grandparent
= aNode
->mParent
) {
245 if (grandparent
->mLeft
== parent
) {
246 grandparent
->mLeft
= aNode
;
248 grandparent
->mRight
= aNode
;
255 T
* checkCoherency(T
* aNode
, T
* aMinimum
) {
257 MOZ_RELEASE_ASSERT(!mRoot
->mParent
);
260 MOZ_RELEASE_ASSERT(!mRoot
);
263 if (!aNode
->mParent
) {
264 MOZ_RELEASE_ASSERT(aNode
== mRoot
);
267 MOZ_RELEASE_ASSERT(Comparator::compare(*aMinimum
, *aNode
) < 0);
270 MOZ_RELEASE_ASSERT(aNode
->mLeft
->mParent
== aNode
);
271 T
* leftMaximum
= checkCoherency(aNode
->mLeft
, aMinimum
);
272 MOZ_RELEASE_ASSERT(Comparator::compare(*leftMaximum
, *aNode
) < 0);
275 MOZ_RELEASE_ASSERT(aNode
->mRight
->mParent
== aNode
);
276 return checkCoherency(aNode
->mRight
, aNode
);
281 SplayTree(const SplayTree
&) = delete;
282 void operator=(const SplayTree
&) = delete;
285 template <typename T
, class Comparator
>
286 T
* SplayTree
<T
, Comparator
>::findOrInsert(const T
& aValue
) {
288 mRoot
= new T(aValue
);
292 T
* last
= lookup(aValue
);
293 int cmp
= Comparator::compare(aValue
, *last
);
298 T
* t
= new T(aValue
);
299 finishInsertion(last
, cmp
, t
);
303 } /* namespace mozilla */
305 #endif /* mozilla_SplayTree_h */