Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===--- ImmutableSet.h - Immutable (functional) set interface --*- C++ -*-===// |
2 | // |
||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
4 | // See https://llvm.org/LICENSE.txt for license information. |
||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
6 | // |
||
7 | //===----------------------------------------------------------------------===// |
||
8 | /// |
||
9 | /// \file |
||
10 | /// This file defines the ImutAVLTree and ImmutableSet classes. |
||
11 | /// |
||
12 | //===----------------------------------------------------------------------===// |
||
13 | |||
14 | #ifndef LLVM_ADT_IMMUTABLESET_H |
||
15 | #define LLVM_ADT_IMMUTABLESET_H |
||
16 | |||
17 | #include "llvm/ADT/DenseMap.h" |
||
18 | #include "llvm/ADT/FoldingSet.h" |
||
19 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
||
20 | #include "llvm/ADT/SmallVector.h" |
||
21 | #include "llvm/ADT/iterator.h" |
||
22 | #include "llvm/Support/Allocator.h" |
||
23 | #include "llvm/Support/ErrorHandling.h" |
||
24 | #include <cassert> |
||
25 | #include <cstdint> |
||
26 | #include <functional> |
||
27 | #include <iterator> |
||
28 | #include <new> |
||
29 | #include <vector> |
||
30 | |||
31 | namespace llvm { |
||
32 | |||
33 | //===----------------------------------------------------------------------===// |
||
34 | // Immutable AVL-Tree Definition. |
||
35 | //===----------------------------------------------------------------------===// |
||
36 | |||
37 | template <typename ImutInfo> class ImutAVLFactory; |
||
38 | template <typename ImutInfo> class ImutIntervalAVLFactory; |
||
39 | template <typename ImutInfo> class ImutAVLTreeInOrderIterator; |
||
40 | template <typename ImutInfo> class ImutAVLTreeGenericIterator; |
||
41 | |||
42 | template <typename ImutInfo > |
||
43 | class ImutAVLTree { |
||
44 | public: |
||
45 | using key_type_ref = typename ImutInfo::key_type_ref; |
||
46 | using value_type = typename ImutInfo::value_type; |
||
47 | using value_type_ref = typename ImutInfo::value_type_ref; |
||
48 | using Factory = ImutAVLFactory<ImutInfo>; |
||
49 | using iterator = ImutAVLTreeInOrderIterator<ImutInfo>; |
||
50 | |||
51 | friend class ImutAVLFactory<ImutInfo>; |
||
52 | friend class ImutIntervalAVLFactory<ImutInfo>; |
||
53 | friend class ImutAVLTreeGenericIterator<ImutInfo>; |
||
54 | |||
55 | //===----------------------------------------------------===// |
||
56 | // Public Interface. |
||
57 | //===----------------------------------------------------===// |
||
58 | |||
59 | /// Return a pointer to the left subtree. This value |
||
60 | /// is NULL if there is no left subtree. |
||
61 | ImutAVLTree *getLeft() const { return left; } |
||
62 | |||
63 | /// Return a pointer to the right subtree. This value is |
||
64 | /// NULL if there is no right subtree. |
||
65 | ImutAVLTree *getRight() const { return right; } |
||
66 | |||
67 | /// getHeight - Returns the height of the tree. A tree with no subtrees |
||
68 | /// has a height of 1. |
||
69 | unsigned getHeight() const { return height; } |
||
70 | |||
71 | /// getValue - Returns the data value associated with the tree node. |
||
72 | const value_type& getValue() const { return value; } |
||
73 | |||
74 | /// find - Finds the subtree associated with the specified key value. |
||
75 | /// This method returns NULL if no matching subtree is found. |
||
76 | ImutAVLTree* find(key_type_ref K) { |
||
77 | ImutAVLTree *T = this; |
||
78 | while (T) { |
||
79 | key_type_ref CurrentKey = ImutInfo::KeyOfValue(T->getValue()); |
||
80 | if (ImutInfo::isEqual(K,CurrentKey)) |
||
81 | return T; |
||
82 | else if (ImutInfo::isLess(K,CurrentKey)) |
||
83 | T = T->getLeft(); |
||
84 | else |
||
85 | T = T->getRight(); |
||
86 | } |
||
87 | return nullptr; |
||
88 | } |
||
89 | |||
90 | /// getMaxElement - Find the subtree associated with the highest ranged |
||
91 | /// key value. |
||
92 | ImutAVLTree* getMaxElement() { |
||
93 | ImutAVLTree *T = this; |
||
94 | ImutAVLTree *Right = T->getRight(); |
||
95 | while (Right) { T = Right; Right = T->getRight(); } |
||
96 | return T; |
||
97 | } |
||
98 | |||
99 | /// size - Returns the number of nodes in the tree, which includes |
||
100 | /// both leaves and non-leaf nodes. |
||
101 | unsigned size() const { |
||
102 | unsigned n = 1; |
||
103 | if (const ImutAVLTree* L = getLeft()) |
||
104 | n += L->size(); |
||
105 | if (const ImutAVLTree* R = getRight()) |
||
106 | n += R->size(); |
||
107 | return n; |
||
108 | } |
||
109 | |||
110 | /// begin - Returns an iterator that iterates over the nodes of the tree |
||
111 | /// in an inorder traversal. The returned iterator thus refers to the |
||
112 | /// the tree node with the minimum data element. |
||
113 | iterator begin() const { return iterator(this); } |
||
114 | |||
115 | /// end - Returns an iterator for the tree that denotes the end of an |
||
116 | /// inorder traversal. |
||
117 | iterator end() const { return iterator(); } |
||
118 | |||
119 | bool isElementEqual(value_type_ref V) const { |
||
120 | // Compare the keys. |
||
121 | if (!ImutInfo::isEqual(ImutInfo::KeyOfValue(getValue()), |
||
122 | ImutInfo::KeyOfValue(V))) |
||
123 | return false; |
||
124 | |||
125 | // Also compare the data values. |
||
126 | if (!ImutInfo::isDataEqual(ImutInfo::DataOfValue(getValue()), |
||
127 | ImutInfo::DataOfValue(V))) |
||
128 | return false; |
||
129 | |||
130 | return true; |
||
131 | } |
||
132 | |||
133 | bool isElementEqual(const ImutAVLTree* RHS) const { |
||
134 | return isElementEqual(RHS->getValue()); |
||
135 | } |
||
136 | |||
137 | /// isEqual - Compares two trees for structural equality and returns true |
||
138 | /// if they are equal. This worst case performance of this operation is |
||
139 | // linear in the sizes of the trees. |
||
140 | bool isEqual(const ImutAVLTree& RHS) const { |
||
141 | if (&RHS == this) |
||
142 | return true; |
||
143 | |||
144 | iterator LItr = begin(), LEnd = end(); |
||
145 | iterator RItr = RHS.begin(), REnd = RHS.end(); |
||
146 | |||
147 | while (LItr != LEnd && RItr != REnd) { |
||
148 | if (&*LItr == &*RItr) { |
||
149 | LItr.skipSubTree(); |
||
150 | RItr.skipSubTree(); |
||
151 | continue; |
||
152 | } |
||
153 | |||
154 | if (!LItr->isElementEqual(&*RItr)) |
||
155 | return false; |
||
156 | |||
157 | ++LItr; |
||
158 | ++RItr; |
||
159 | } |
||
160 | |||
161 | return LItr == LEnd && RItr == REnd; |
||
162 | } |
||
163 | |||
164 | /// isNotEqual - Compares two trees for structural inequality. Performance |
||
165 | /// is the same is isEqual. |
||
166 | bool isNotEqual(const ImutAVLTree& RHS) const { return !isEqual(RHS); } |
||
167 | |||
168 | /// contains - Returns true if this tree contains a subtree (node) that |
||
169 | /// has an data element that matches the specified key. Complexity |
||
170 | /// is logarithmic in the size of the tree. |
||
171 | bool contains(key_type_ref K) { return (bool) find(K); } |
||
172 | |||
173 | /// validateTree - A utility method that checks that the balancing and |
||
174 | /// ordering invariants of the tree are satisfied. It is a recursive |
||
175 | /// method that returns the height of the tree, which is then consumed |
||
176 | /// by the enclosing validateTree call. External callers should ignore the |
||
177 | /// return value. An invalid tree will cause an assertion to fire in |
||
178 | /// a debug build. |
||
179 | unsigned validateTree() const { |
||
180 | unsigned HL = getLeft() ? getLeft()->validateTree() : 0; |
||
181 | unsigned HR = getRight() ? getRight()->validateTree() : 0; |
||
182 | (void) HL; |
||
183 | (void) HR; |
||
184 | |||
185 | assert(getHeight() == ( HL > HR ? HL : HR ) + 1 |
||
186 | && "Height calculation wrong"); |
||
187 | |||
188 | assert((HL > HR ? HL-HR : HR-HL) <= 2 |
||
189 | && "Balancing invariant violated"); |
||
190 | |||
191 | assert((!getLeft() || |
||
192 | ImutInfo::isLess(ImutInfo::KeyOfValue(getLeft()->getValue()), |
||
193 | ImutInfo::KeyOfValue(getValue()))) && |
||
194 | "Value in left child is not less that current value"); |
||
195 | |||
196 | assert((!getRight() || |
||
197 | ImutInfo::isLess(ImutInfo::KeyOfValue(getValue()), |
||
198 | ImutInfo::KeyOfValue(getRight()->getValue()))) && |
||
199 | "Current value is not less that value of right child"); |
||
200 | |||
201 | return getHeight(); |
||
202 | } |
||
203 | |||
204 | //===----------------------------------------------------===// |
||
205 | // Internal values. |
||
206 | //===----------------------------------------------------===// |
||
207 | |||
208 | private: |
||
209 | Factory *factory; |
||
210 | ImutAVLTree *left; |
||
211 | ImutAVLTree *right; |
||
212 | ImutAVLTree *prev = nullptr; |
||
213 | ImutAVLTree *next = nullptr; |
||
214 | |||
215 | unsigned height : 28; |
||
216 | bool IsMutable : 1; |
||
217 | bool IsDigestCached : 1; |
||
218 | bool IsCanonicalized : 1; |
||
219 | |||
220 | value_type value; |
||
221 | uint32_t digest = 0; |
||
222 | uint32_t refCount = 0; |
||
223 | |||
224 | //===----------------------------------------------------===// |
||
225 | // Internal methods (node manipulation; used by Factory). |
||
226 | //===----------------------------------------------------===// |
||
227 | |||
228 | private: |
||
229 | /// ImutAVLTree - Internal constructor that is only called by |
||
230 | /// ImutAVLFactory. |
||
231 | ImutAVLTree(Factory *f, ImutAVLTree* l, ImutAVLTree* r, value_type_ref v, |
||
232 | unsigned height) |
||
233 | : factory(f), left(l), right(r), height(height), IsMutable(true), |
||
234 | IsDigestCached(false), IsCanonicalized(false), value(v) |
||
235 | { |
||
236 | if (left) left->retain(); |
||
237 | if (right) right->retain(); |
||
238 | } |
||
239 | |||
240 | /// isMutable - Returns true if the left and right subtree references |
||
241 | /// (as well as height) can be changed. If this method returns false, |
||
242 | /// the tree is truly immutable. Trees returned from an ImutAVLFactory |
||
243 | /// object should always have this method return true. Further, if this |
||
244 | /// method returns false for an instance of ImutAVLTree, all subtrees |
||
245 | /// will also have this method return false. The converse is not true. |
||
246 | bool isMutable() const { return IsMutable; } |
||
247 | |||
248 | /// hasCachedDigest - Returns true if the digest for this tree is cached. |
||
249 | /// This can only be true if the tree is immutable. |
||
250 | bool hasCachedDigest() const { return IsDigestCached; } |
||
251 | |||
252 | //===----------------------------------------------------===// |
||
253 | // Mutating operations. A tree root can be manipulated as |
||
254 | // long as its reference has not "escaped" from internal |
||
255 | // methods of a factory object (see below). When a tree |
||
256 | // pointer is externally viewable by client code, the |
||
257 | // internal "mutable bit" is cleared to mark the tree |
||
258 | // immutable. Note that a tree that still has its mutable |
||
259 | // bit set may have children (subtrees) that are themselves |
||
260 | // immutable. |
||
261 | //===----------------------------------------------------===// |
||
262 | |||
263 | /// markImmutable - Clears the mutable flag for a tree. After this happens, |
||
264 | /// it is an error to call setLeft(), setRight(), and setHeight(). |
||
265 | void markImmutable() { |
||
266 | assert(isMutable() && "Mutable flag already removed."); |
||
267 | IsMutable = false; |
||
268 | } |
||
269 | |||
270 | /// markedCachedDigest - Clears the NoCachedDigest flag for a tree. |
||
271 | void markedCachedDigest() { |
||
272 | assert(!hasCachedDigest() && "NoCachedDigest flag already removed."); |
||
273 | IsDigestCached = true; |
||
274 | } |
||
275 | |||
276 | /// setHeight - Changes the height of the tree. Used internally by |
||
277 | /// ImutAVLFactory. |
||
278 | void setHeight(unsigned h) { |
||
279 | assert(isMutable() && "Only a mutable tree can have its height changed."); |
||
280 | height = h; |
||
281 | } |
||
282 | |||
283 | static uint32_t computeDigest(ImutAVLTree *L, ImutAVLTree *R, |
||
284 | value_type_ref V) { |
||
285 | uint32_t digest = 0; |
||
286 | |||
287 | if (L) |
||
288 | digest += L->computeDigest(); |
||
289 | |||
290 | // Compute digest of stored data. |
||
291 | FoldingSetNodeID ID; |
||
292 | ImutInfo::Profile(ID,V); |
||
293 | digest += ID.ComputeHash(); |
||
294 | |||
295 | if (R) |
||
296 | digest += R->computeDigest(); |
||
297 | |||
298 | return digest; |
||
299 | } |
||
300 | |||
301 | uint32_t computeDigest() { |
||
302 | // Check the lowest bit to determine if digest has actually been |
||
303 | // pre-computed. |
||
304 | if (hasCachedDigest()) |
||
305 | return digest; |
||
306 | |||
307 | uint32_t X = computeDigest(getLeft(), getRight(), getValue()); |
||
308 | digest = X; |
||
309 | markedCachedDigest(); |
||
310 | return X; |
||
311 | } |
||
312 | |||
313 | //===----------------------------------------------------===// |
||
314 | // Reference count operations. |
||
315 | //===----------------------------------------------------===// |
||
316 | |||
317 | public: |
||
318 | void retain() { ++refCount; } |
||
319 | |||
320 | void release() { |
||
321 | assert(refCount > 0); |
||
322 | if (--refCount == 0) |
||
323 | destroy(); |
||
324 | } |
||
325 | |||
326 | void destroy() { |
||
327 | if (left) |
||
328 | left->release(); |
||
329 | if (right) |
||
330 | right->release(); |
||
331 | if (IsCanonicalized) { |
||
332 | if (next) |
||
333 | next->prev = prev; |
||
334 | |||
335 | if (prev) |
||
336 | prev->next = next; |
||
337 | else |
||
338 | factory->Cache[factory->maskCacheIndex(computeDigest())] = next; |
||
339 | } |
||
340 | |||
341 | // We need to clear the mutability bit in case we are |
||
342 | // destroying the node as part of a sweep in ImutAVLFactory::recoverNodes(). |
||
343 | IsMutable = false; |
||
344 | factory->freeNodes.push_back(this); |
||
345 | } |
||
346 | }; |
||
347 | |||
348 | template <typename ImutInfo> |
||
349 | struct IntrusiveRefCntPtrInfo<ImutAVLTree<ImutInfo>> { |
||
350 | static void retain(ImutAVLTree<ImutInfo> *Tree) { Tree->retain(); } |
||
351 | static void release(ImutAVLTree<ImutInfo> *Tree) { Tree->release(); } |
||
352 | }; |
||
353 | |||
354 | //===----------------------------------------------------------------------===// |
||
355 | // Immutable AVL-Tree Factory class. |
||
356 | //===----------------------------------------------------------------------===// |
||
357 | |||
358 | template <typename ImutInfo > |
||
359 | class ImutAVLFactory { |
||
360 | friend class ImutAVLTree<ImutInfo>; |
||
361 | |||
362 | using TreeTy = ImutAVLTree<ImutInfo>; |
||
363 | using value_type_ref = typename TreeTy::value_type_ref; |
||
364 | using key_type_ref = typename TreeTy::key_type_ref; |
||
365 | using CacheTy = DenseMap<unsigned, TreeTy*>; |
||
366 | |||
367 | CacheTy Cache; |
||
368 | uintptr_t Allocator; |
||
369 | std::vector<TreeTy*> createdNodes; |
||
370 | std::vector<TreeTy*> freeNodes; |
||
371 | |||
372 | bool ownsAllocator() const { |
||
373 | return (Allocator & 0x1) == 0; |
||
374 | } |
||
375 | |||
376 | BumpPtrAllocator& getAllocator() const { |
||
377 | return *reinterpret_cast<BumpPtrAllocator*>(Allocator & ~0x1); |
||
378 | } |
||
379 | |||
380 | //===--------------------------------------------------===// |
||
381 | // Public interface. |
||
382 | //===--------------------------------------------------===// |
||
383 | |||
384 | public: |
||
385 | ImutAVLFactory() |
||
386 | : Allocator(reinterpret_cast<uintptr_t>(new BumpPtrAllocator())) {} |
||
387 | |||
388 | ImutAVLFactory(BumpPtrAllocator& Alloc) |
||
389 | : Allocator(reinterpret_cast<uintptr_t>(&Alloc) | 0x1) {} |
||
390 | |||
391 | ~ImutAVLFactory() { |
||
392 | if (ownsAllocator()) delete &getAllocator(); |
||
393 | } |
||
394 | |||
395 | TreeTy* add(TreeTy* T, value_type_ref V) { |
||
396 | T = add_internal(V,T); |
||
397 | markImmutable(T); |
||
398 | recoverNodes(); |
||
399 | return T; |
||
400 | } |
||
401 | |||
402 | TreeTy* remove(TreeTy* T, key_type_ref V) { |
||
403 | T = remove_internal(V,T); |
||
404 | markImmutable(T); |
||
405 | recoverNodes(); |
||
406 | return T; |
||
407 | } |
||
408 | |||
409 | TreeTy* getEmptyTree() const { return nullptr; } |
||
410 | |||
411 | protected: |
||
412 | //===--------------------------------------------------===// |
||
413 | // A bunch of quick helper functions used for reasoning |
||
414 | // about the properties of trees and their children. |
||
415 | // These have succinct names so that the balancing code |
||
416 | // is as terse (and readable) as possible. |
||
417 | //===--------------------------------------------------===// |
||
418 | |||
419 | bool isEmpty(TreeTy* T) const { return !T; } |
||
420 | unsigned getHeight(TreeTy* T) const { return T ? T->getHeight() : 0; } |
||
421 | TreeTy* getLeft(TreeTy* T) const { return T->getLeft(); } |
||
422 | TreeTy* getRight(TreeTy* T) const { return T->getRight(); } |
||
423 | value_type_ref getValue(TreeTy* T) const { return T->value; } |
||
424 | |||
425 | // Make sure the index is not the Tombstone or Entry key of the DenseMap. |
||
426 | static unsigned maskCacheIndex(unsigned I) { return (I & ~0x02); } |
||
427 | |||
428 | unsigned incrementHeight(TreeTy* L, TreeTy* R) const { |
||
429 | unsigned hl = getHeight(L); |
||
430 | unsigned hr = getHeight(R); |
||
431 | return (hl > hr ? hl : hr) + 1; |
||
432 | } |
||
433 | |||
434 | static bool compareTreeWithSection(TreeTy* T, |
||
435 | typename TreeTy::iterator& TI, |
||
436 | typename TreeTy::iterator& TE) { |
||
437 | typename TreeTy::iterator I = T->begin(), E = T->end(); |
||
438 | for ( ; I!=E ; ++I, ++TI) { |
||
439 | if (TI == TE || !I->isElementEqual(&*TI)) |
||
440 | return false; |
||
441 | } |
||
442 | return true; |
||
443 | } |
||
444 | |||
445 | //===--------------------------------------------------===// |
||
446 | // "createNode" is used to generate new tree roots that link |
||
447 | // to other trees. The function may also simply move links |
||
448 | // in an existing root if that root is still marked mutable. |
||
449 | // This is necessary because otherwise our balancing code |
||
450 | // would leak memory as it would create nodes that are |
||
451 | // then discarded later before the finished tree is |
||
452 | // returned to the caller. |
||
453 | //===--------------------------------------------------===// |
||
454 | |||
455 | TreeTy* createNode(TreeTy* L, value_type_ref V, TreeTy* R) { |
||
456 | BumpPtrAllocator& A = getAllocator(); |
||
457 | TreeTy* T; |
||
458 | if (!freeNodes.empty()) { |
||
459 | T = freeNodes.back(); |
||
460 | freeNodes.pop_back(); |
||
461 | assert(T != L); |
||
462 | assert(T != R); |
||
463 | } else { |
||
464 | T = (TreeTy*) A.Allocate<TreeTy>(); |
||
465 | } |
||
466 | new (T) TreeTy(this, L, R, V, incrementHeight(L,R)); |
||
467 | createdNodes.push_back(T); |
||
468 | return T; |
||
469 | } |
||
470 | |||
471 | TreeTy* createNode(TreeTy* newLeft, TreeTy* oldTree, TreeTy* newRight) { |
||
472 | return createNode(newLeft, getValue(oldTree), newRight); |
||
473 | } |
||
474 | |||
475 | void recoverNodes() { |
||
476 | for (unsigned i = 0, n = createdNodes.size(); i < n; ++i) { |
||
477 | TreeTy *N = createdNodes[i]; |
||
478 | if (N->isMutable() && N->refCount == 0) |
||
479 | N->destroy(); |
||
480 | } |
||
481 | createdNodes.clear(); |
||
482 | } |
||
483 | |||
484 | /// balanceTree - Used by add_internal and remove_internal to |
||
485 | /// balance a newly created tree. |
||
486 | TreeTy* balanceTree(TreeTy* L, value_type_ref V, TreeTy* R) { |
||
487 | unsigned hl = getHeight(L); |
||
488 | unsigned hr = getHeight(R); |
||
489 | |||
490 | if (hl > hr + 2) { |
||
491 | assert(!isEmpty(L) && "Left tree cannot be empty to have a height >= 2"); |
||
492 | |||
493 | TreeTy *LL = getLeft(L); |
||
494 | TreeTy *LR = getRight(L); |
||
495 | |||
496 | if (getHeight(LL) >= getHeight(LR)) |
||
497 | return createNode(LL, L, createNode(LR,V,R)); |
||
498 | |||
499 | assert(!isEmpty(LR) && "LR cannot be empty because it has a height >= 1"); |
||
500 | |||
501 | TreeTy *LRL = getLeft(LR); |
||
502 | TreeTy *LRR = getRight(LR); |
||
503 | |||
504 | return createNode(createNode(LL,L,LRL), LR, createNode(LRR,V,R)); |
||
505 | } |
||
506 | |||
507 | if (hr > hl + 2) { |
||
508 | assert(!isEmpty(R) && "Right tree cannot be empty to have a height >= 2"); |
||
509 | |||
510 | TreeTy *RL = getLeft(R); |
||
511 | TreeTy *RR = getRight(R); |
||
512 | |||
513 | if (getHeight(RR) >= getHeight(RL)) |
||
514 | return createNode(createNode(L,V,RL), R, RR); |
||
515 | |||
516 | assert(!isEmpty(RL) && "RL cannot be empty because it has a height >= 1"); |
||
517 | |||
518 | TreeTy *RLL = getLeft(RL); |
||
519 | TreeTy *RLR = getRight(RL); |
||
520 | |||
521 | return createNode(createNode(L,V,RLL), RL, createNode(RLR,R,RR)); |
||
522 | } |
||
523 | |||
524 | return createNode(L,V,R); |
||
525 | } |
||
526 | |||
527 | /// add_internal - Creates a new tree that includes the specified |
||
528 | /// data and the data from the original tree. If the original tree |
||
529 | /// already contained the data item, the original tree is returned. |
||
530 | TreeTy* add_internal(value_type_ref V, TreeTy* T) { |
||
531 | if (isEmpty(T)) |
||
532 | return createNode(T, V, T); |
||
533 | assert(!T->isMutable()); |
||
534 | |||
535 | key_type_ref K = ImutInfo::KeyOfValue(V); |
||
536 | key_type_ref KCurrent = ImutInfo::KeyOfValue(getValue(T)); |
||
537 | |||
538 | if (ImutInfo::isEqual(K,KCurrent)) |
||
539 | return createNode(getLeft(T), V, getRight(T)); |
||
540 | else if (ImutInfo::isLess(K,KCurrent)) |
||
541 | return balanceTree(add_internal(V, getLeft(T)), getValue(T), getRight(T)); |
||
542 | else |
||
543 | return balanceTree(getLeft(T), getValue(T), add_internal(V, getRight(T))); |
||
544 | } |
||
545 | |||
546 | /// remove_internal - Creates a new tree that includes all the data |
||
547 | /// from the original tree except the specified data. If the |
||
548 | /// specified data did not exist in the original tree, the original |
||
549 | /// tree is returned. |
||
550 | TreeTy* remove_internal(key_type_ref K, TreeTy* T) { |
||
551 | if (isEmpty(T)) |
||
552 | return T; |
||
553 | |||
554 | assert(!T->isMutable()); |
||
555 | |||
556 | key_type_ref KCurrent = ImutInfo::KeyOfValue(getValue(T)); |
||
557 | |||
558 | if (ImutInfo::isEqual(K,KCurrent)) { |
||
559 | return combineTrees(getLeft(T), getRight(T)); |
||
560 | } else if (ImutInfo::isLess(K,KCurrent)) { |
||
561 | return balanceTree(remove_internal(K, getLeft(T)), |
||
562 | getValue(T), getRight(T)); |
||
563 | } else { |
||
564 | return balanceTree(getLeft(T), getValue(T), |
||
565 | remove_internal(K, getRight(T))); |
||
566 | } |
||
567 | } |
||
568 | |||
569 | TreeTy* combineTrees(TreeTy* L, TreeTy* R) { |
||
570 | if (isEmpty(L)) |
||
571 | return R; |
||
572 | if (isEmpty(R)) |
||
573 | return L; |
||
574 | TreeTy* OldNode; |
||
575 | TreeTy* newRight = removeMinBinding(R,OldNode); |
||
576 | return balanceTree(L, getValue(OldNode), newRight); |
||
577 | } |
||
578 | |||
579 | TreeTy* removeMinBinding(TreeTy* T, TreeTy*& Noderemoved) { |
||
580 | assert(!isEmpty(T)); |
||
581 | if (isEmpty(getLeft(T))) { |
||
582 | Noderemoved = T; |
||
583 | return getRight(T); |
||
584 | } |
||
585 | return balanceTree(removeMinBinding(getLeft(T), Noderemoved), |
||
586 | getValue(T), getRight(T)); |
||
587 | } |
||
588 | |||
589 | /// markImmutable - Clears the mutable bits of a root and all of its |
||
590 | /// descendants. |
||
591 | void markImmutable(TreeTy* T) { |
||
592 | if (!T || !T->isMutable()) |
||
593 | return; |
||
594 | T->markImmutable(); |
||
595 | markImmutable(getLeft(T)); |
||
596 | markImmutable(getRight(T)); |
||
597 | } |
||
598 | |||
599 | public: |
||
600 | TreeTy *getCanonicalTree(TreeTy *TNew) { |
||
601 | if (!TNew) |
||
602 | return nullptr; |
||
603 | |||
604 | if (TNew->IsCanonicalized) |
||
605 | return TNew; |
||
606 | |||
607 | // Search the hashtable for another tree with the same digest, and |
||
608 | // if find a collision compare those trees by their contents. |
||
609 | unsigned digest = TNew->computeDigest(); |
||
610 | TreeTy *&entry = Cache[maskCacheIndex(digest)]; |
||
611 | do { |
||
612 | if (!entry) |
||
613 | break; |
||
614 | for (TreeTy *T = entry ; T != nullptr; T = T->next) { |
||
615 | // Compare the Contents('T') with Contents('TNew') |
||
616 | typename TreeTy::iterator TI = T->begin(), TE = T->end(); |
||
617 | if (!compareTreeWithSection(TNew, TI, TE)) |
||
618 | continue; |
||
619 | if (TI != TE) |
||
620 | continue; // T has more contents than TNew. |
||
621 | // Trees did match! Return 'T'. |
||
622 | if (TNew->refCount == 0) |
||
623 | TNew->destroy(); |
||
624 | return T; |
||
625 | } |
||
626 | entry->prev = TNew; |
||
627 | TNew->next = entry; |
||
628 | } |
||
629 | while (false); |
||
630 | |||
631 | entry = TNew; |
||
632 | TNew->IsCanonicalized = true; |
||
633 | return TNew; |
||
634 | } |
||
635 | }; |
||
636 | |||
637 | //===----------------------------------------------------------------------===// |
||
638 | // Immutable AVL-Tree Iterators. |
||
639 | //===----------------------------------------------------------------------===// |
||
640 | |||
641 | template <typename ImutInfo> class ImutAVLTreeGenericIterator { |
||
642 | SmallVector<uintptr_t,20> stack; |
||
643 | |||
644 | public: |
||
645 | using iterator_category = std::bidirectional_iterator_tag; |
||
646 | using value_type = ImutAVLTree<ImutInfo>; |
||
647 | using difference_type = std::ptrdiff_t; |
||
648 | using pointer = value_type *; |
||
649 | using reference = value_type &; |
||
650 | |||
651 | enum VisitFlag { VisitedNone=0x0, VisitedLeft=0x1, VisitedRight=0x3, |
||
652 | Flags=0x3 }; |
||
653 | |||
654 | using TreeTy = ImutAVLTree<ImutInfo>; |
||
655 | |||
656 | ImutAVLTreeGenericIterator() = default; |
||
657 | ImutAVLTreeGenericIterator(const TreeTy *Root) { |
||
658 | if (Root) stack.push_back(reinterpret_cast<uintptr_t>(Root)); |
||
659 | } |
||
660 | |||
661 | TreeTy &operator*() const { |
||
662 | assert(!stack.empty()); |
||
663 | return *reinterpret_cast<TreeTy *>(stack.back() & ~Flags); |
||
664 | } |
||
665 | TreeTy *operator->() const { return &*this; } |
||
666 | |||
667 | uintptr_t getVisitState() const { |
||
668 | assert(!stack.empty()); |
||
669 | return stack.back() & Flags; |
||
670 | } |
||
671 | |||
672 | bool atEnd() const { return stack.empty(); } |
||
673 | |||
674 | bool atBeginning() const { |
||
675 | return stack.size() == 1 && getVisitState() == VisitedNone; |
||
676 | } |
||
677 | |||
678 | void skipToParent() { |
||
679 | assert(!stack.empty()); |
||
680 | stack.pop_back(); |
||
681 | if (stack.empty()) |
||
682 | return; |
||
683 | switch (getVisitState()) { |
||
684 | case VisitedNone: |
||
685 | stack.back() |= VisitedLeft; |
||
686 | break; |
||
687 | case VisitedLeft: |
||
688 | stack.back() |= VisitedRight; |
||
689 | break; |
||
690 | default: |
||
691 | llvm_unreachable("Unreachable."); |
||
692 | } |
||
693 | } |
||
694 | |||
695 | bool operator==(const ImutAVLTreeGenericIterator &x) const { |
||
696 | return stack == x.stack; |
||
697 | } |
||
698 | |||
699 | bool operator!=(const ImutAVLTreeGenericIterator &x) const { |
||
700 | return !(*this == x); |
||
701 | } |
||
702 | |||
703 | ImutAVLTreeGenericIterator &operator++() { |
||
704 | assert(!stack.empty()); |
||
705 | TreeTy* Current = reinterpret_cast<TreeTy*>(stack.back() & ~Flags); |
||
706 | assert(Current); |
||
707 | switch (getVisitState()) { |
||
708 | case VisitedNone: |
||
709 | if (TreeTy* L = Current->getLeft()) |
||
710 | stack.push_back(reinterpret_cast<uintptr_t>(L)); |
||
711 | else |
||
712 | stack.back() |= VisitedLeft; |
||
713 | break; |
||
714 | case VisitedLeft: |
||
715 | if (TreeTy* R = Current->getRight()) |
||
716 | stack.push_back(reinterpret_cast<uintptr_t>(R)); |
||
717 | else |
||
718 | stack.back() |= VisitedRight; |
||
719 | break; |
||
720 | case VisitedRight: |
||
721 | skipToParent(); |
||
722 | break; |
||
723 | default: |
||
724 | llvm_unreachable("Unreachable."); |
||
725 | } |
||
726 | return *this; |
||
727 | } |
||
728 | |||
729 | ImutAVLTreeGenericIterator &operator--() { |
||
730 | assert(!stack.empty()); |
||
731 | TreeTy* Current = reinterpret_cast<TreeTy*>(stack.back() & ~Flags); |
||
732 | assert(Current); |
||
733 | switch (getVisitState()) { |
||
734 | case VisitedNone: |
||
735 | stack.pop_back(); |
||
736 | break; |
||
737 | case VisitedLeft: |
||
738 | stack.back() &= ~Flags; // Set state to "VisitedNone." |
||
739 | if (TreeTy* L = Current->getLeft()) |
||
740 | stack.push_back(reinterpret_cast<uintptr_t>(L) | VisitedRight); |
||
741 | break; |
||
742 | case VisitedRight: |
||
743 | stack.back() &= ~Flags; |
||
744 | stack.back() |= VisitedLeft; |
||
745 | if (TreeTy* R = Current->getRight()) |
||
746 | stack.push_back(reinterpret_cast<uintptr_t>(R) | VisitedRight); |
||
747 | break; |
||
748 | default: |
||
749 | llvm_unreachable("Unreachable."); |
||
750 | } |
||
751 | return *this; |
||
752 | } |
||
753 | }; |
||
754 | |||
755 | template <typename ImutInfo> class ImutAVLTreeInOrderIterator { |
||
756 | using InternalIteratorTy = ImutAVLTreeGenericIterator<ImutInfo>; |
||
757 | |||
758 | InternalIteratorTy InternalItr; |
||
759 | |||
760 | public: |
||
761 | using iterator_category = std::bidirectional_iterator_tag; |
||
762 | using value_type = ImutAVLTree<ImutInfo>; |
||
763 | using difference_type = std::ptrdiff_t; |
||
764 | using pointer = value_type *; |
||
765 | using reference = value_type &; |
||
766 | |||
767 | using TreeTy = ImutAVLTree<ImutInfo>; |
||
768 | |||
769 | ImutAVLTreeInOrderIterator(const TreeTy* Root) : InternalItr(Root) { |
||
770 | if (Root) |
||
771 | ++*this; // Advance to first element. |
||
772 | } |
||
773 | |||
774 | ImutAVLTreeInOrderIterator() : InternalItr() {} |
||
775 | |||
776 | bool operator==(const ImutAVLTreeInOrderIterator &x) const { |
||
777 | return InternalItr == x.InternalItr; |
||
778 | } |
||
779 | |||
780 | bool operator!=(const ImutAVLTreeInOrderIterator &x) const { |
||
781 | return !(*this == x); |
||
782 | } |
||
783 | |||
784 | TreeTy &operator*() const { return *InternalItr; } |
||
785 | TreeTy *operator->() const { return &*InternalItr; } |
||
786 | |||
787 | ImutAVLTreeInOrderIterator &operator++() { |
||
788 | do ++InternalItr; |
||
789 | while (!InternalItr.atEnd() && |
||
790 | InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft); |
||
791 | |||
792 | return *this; |
||
793 | } |
||
794 | |||
795 | ImutAVLTreeInOrderIterator &operator--() { |
||
796 | do --InternalItr; |
||
797 | while (!InternalItr.atBeginning() && |
||
798 | InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft); |
||
799 | |||
800 | return *this; |
||
801 | } |
||
802 | |||
803 | void skipSubTree() { |
||
804 | InternalItr.skipToParent(); |
||
805 | |||
806 | while (!InternalItr.atEnd() && |
||
807 | InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft) |
||
808 | ++InternalItr; |
||
809 | } |
||
810 | }; |
||
811 | |||
812 | /// Generic iterator that wraps a T::TreeTy::iterator and exposes |
||
813 | /// iterator::getValue() on dereference. |
||
814 | template <typename T> |
||
815 | struct ImutAVLValueIterator |
||
816 | : iterator_adaptor_base< |
||
817 | ImutAVLValueIterator<T>, typename T::TreeTy::iterator, |
||
818 | typename std::iterator_traits< |
||
819 | typename T::TreeTy::iterator>::iterator_category, |
||
820 | const typename T::value_type> { |
||
821 | ImutAVLValueIterator() = default; |
||
822 | explicit ImutAVLValueIterator(typename T::TreeTy *Tree) |
||
823 | : ImutAVLValueIterator::iterator_adaptor_base(Tree) {} |
||
824 | |||
825 | typename ImutAVLValueIterator::reference operator*() const { |
||
826 | return this->I->getValue(); |
||
827 | } |
||
828 | }; |
||
829 | |||
830 | //===----------------------------------------------------------------------===// |
||
831 | // Trait classes for Profile information. |
||
832 | //===----------------------------------------------------------------------===// |
||
833 | |||
834 | /// Generic profile template. The default behavior is to invoke the |
||
835 | /// profile method of an object. Specializations for primitive integers |
||
836 | /// and generic handling of pointers is done below. |
||
837 | template <typename T> |
||
838 | struct ImutProfileInfo { |
||
839 | using value_type = const T; |
||
840 | using value_type_ref = const T&; |
||
841 | |||
842 | static void Profile(FoldingSetNodeID &ID, value_type_ref X) { |
||
843 | FoldingSetTrait<T>::Profile(X,ID); |
||
844 | } |
||
845 | }; |
||
846 | |||
847 | /// Profile traits for integers. |
||
848 | template <typename T> |
||
849 | struct ImutProfileInteger { |
||
850 | using value_type = const T; |
||
851 | using value_type_ref = const T&; |
||
852 | |||
853 | static void Profile(FoldingSetNodeID &ID, value_type_ref X) { |
||
854 | ID.AddInteger(X); |
||
855 | } |
||
856 | }; |
||
857 | |||
858 | #define PROFILE_INTEGER_INFO(X)\ |
||
859 | template<> struct ImutProfileInfo<X> : ImutProfileInteger<X> {}; |
||
860 | |||
861 | PROFILE_INTEGER_INFO(char) |
||
862 | PROFILE_INTEGER_INFO(unsigned char) |
||
863 | PROFILE_INTEGER_INFO(short) |
||
864 | PROFILE_INTEGER_INFO(unsigned short) |
||
865 | PROFILE_INTEGER_INFO(unsigned) |
||
866 | PROFILE_INTEGER_INFO(signed) |
||
867 | PROFILE_INTEGER_INFO(long) |
||
868 | PROFILE_INTEGER_INFO(unsigned long) |
||
869 | PROFILE_INTEGER_INFO(long long) |
||
870 | PROFILE_INTEGER_INFO(unsigned long long) |
||
871 | |||
872 | #undef PROFILE_INTEGER_INFO |
||
873 | |||
874 | /// Profile traits for booleans. |
||
875 | template <> |
||
876 | struct ImutProfileInfo<bool> { |
||
877 | using value_type = const bool; |
||
878 | using value_type_ref = const bool&; |
||
879 | |||
880 | static void Profile(FoldingSetNodeID &ID, value_type_ref X) { |
||
881 | ID.AddBoolean(X); |
||
882 | } |
||
883 | }; |
||
884 | |||
885 | /// Generic profile trait for pointer types. We treat pointers as |
||
886 | /// references to unique objects. |
||
887 | template <typename T> |
||
888 | struct ImutProfileInfo<T*> { |
||
889 | using value_type = const T*; |
||
890 | using value_type_ref = value_type; |
||
891 | |||
892 | static void Profile(FoldingSetNodeID &ID, value_type_ref X) { |
||
893 | ID.AddPointer(X); |
||
894 | } |
||
895 | }; |
||
896 | |||
897 | //===----------------------------------------------------------------------===// |
||
898 | // Trait classes that contain element comparison operators and type |
||
899 | // definitions used by ImutAVLTree, ImmutableSet, and ImmutableMap. These |
||
900 | // inherit from the profile traits (ImutProfileInfo) to include operations |
||
901 | // for element profiling. |
||
902 | //===----------------------------------------------------------------------===// |
||
903 | |||
904 | /// ImutContainerInfo - Generic definition of comparison operations for |
||
905 | /// elements of immutable containers that defaults to using |
||
906 | /// std::equal_to<> and std::less<> to perform comparison of elements. |
||
907 | template <typename T> |
||
908 | struct ImutContainerInfo : public ImutProfileInfo<T> { |
||
909 | using value_type = typename ImutProfileInfo<T>::value_type; |
||
910 | using value_type_ref = typename ImutProfileInfo<T>::value_type_ref; |
||
911 | using key_type = value_type; |
||
912 | using key_type_ref = value_type_ref; |
||
913 | using data_type = bool; |
||
914 | using data_type_ref = bool; |
||
915 | |||
916 | static key_type_ref KeyOfValue(value_type_ref D) { return D; } |
||
917 | static data_type_ref DataOfValue(value_type_ref) { return true; } |
||
918 | |||
919 | static bool isEqual(key_type_ref LHS, key_type_ref RHS) { |
||
920 | return std::equal_to<key_type>()(LHS,RHS); |
||
921 | } |
||
922 | |||
923 | static bool isLess(key_type_ref LHS, key_type_ref RHS) { |
||
924 | return std::less<key_type>()(LHS,RHS); |
||
925 | } |
||
926 | |||
927 | static bool isDataEqual(data_type_ref, data_type_ref) { return true; } |
||
928 | }; |
||
929 | |||
930 | /// ImutContainerInfo - Specialization for pointer values to treat pointers |
||
931 | /// as references to unique objects. Pointers are thus compared by |
||
932 | /// their addresses. |
||
933 | template <typename T> |
||
934 | struct ImutContainerInfo<T*> : public ImutProfileInfo<T*> { |
||
935 | using value_type = typename ImutProfileInfo<T*>::value_type; |
||
936 | using value_type_ref = typename ImutProfileInfo<T*>::value_type_ref; |
||
937 | using key_type = value_type; |
||
938 | using key_type_ref = value_type_ref; |
||
939 | using data_type = bool; |
||
940 | using data_type_ref = bool; |
||
941 | |||
942 | static key_type_ref KeyOfValue(value_type_ref D) { return D; } |
||
943 | static data_type_ref DataOfValue(value_type_ref) { return true; } |
||
944 | |||
945 | static bool isEqual(key_type_ref LHS, key_type_ref RHS) { return LHS == RHS; } |
||
946 | |||
947 | static bool isLess(key_type_ref LHS, key_type_ref RHS) { return LHS < RHS; } |
||
948 | |||
949 | static bool isDataEqual(data_type_ref, data_type_ref) { return true; } |
||
950 | }; |
||
951 | |||
952 | //===----------------------------------------------------------------------===// |
||
953 | // Immutable Set |
||
954 | //===----------------------------------------------------------------------===// |
||
955 | |||
956 | template <typename ValT, typename ValInfo = ImutContainerInfo<ValT>> |
||
957 | class ImmutableSet { |
||
958 | public: |
||
959 | using value_type = typename ValInfo::value_type; |
||
960 | using value_type_ref = typename ValInfo::value_type_ref; |
||
961 | using TreeTy = ImutAVLTree<ValInfo>; |
||
962 | |||
963 | private: |
||
964 | IntrusiveRefCntPtr<TreeTy> Root; |
||
965 | |||
966 | public: |
||
967 | /// Constructs a set from a pointer to a tree root. In general one |
||
968 | /// should use a Factory object to create sets instead of directly |
||
969 | /// invoking the constructor, but there are cases where make this |
||
970 | /// constructor public is useful. |
||
971 | explicit ImmutableSet(TreeTy *R) : Root(R) {} |
||
972 | |||
973 | class Factory { |
||
974 | typename TreeTy::Factory F; |
||
975 | const bool Canonicalize; |
||
976 | |||
977 | public: |
||
978 | Factory(bool canonicalize = true) |
||
979 | : Canonicalize(canonicalize) {} |
||
980 | |||
981 | Factory(BumpPtrAllocator& Alloc, bool canonicalize = true) |
||
982 | : F(Alloc), Canonicalize(canonicalize) {} |
||
983 | |||
984 | Factory(const Factory& RHS) = delete; |
||
985 | void operator=(const Factory& RHS) = delete; |
||
986 | |||
987 | /// getEmptySet - Returns an immutable set that contains no elements. |
||
988 | ImmutableSet getEmptySet() { |
||
989 | return ImmutableSet(F.getEmptyTree()); |
||
990 | } |
||
991 | |||
992 | /// add - Creates a new immutable set that contains all of the values |
||
993 | /// of the original set with the addition of the specified value. If |
||
994 | /// the original set already included the value, then the original set is |
||
995 | /// returned and no memory is allocated. The time and space complexity |
||
996 | /// of this operation is logarithmic in the size of the original set. |
||
997 | /// The memory allocated to represent the set is released when the |
||
998 | /// factory object that created the set is destroyed. |
||
999 | [[nodiscard]] ImmutableSet add(ImmutableSet Old, value_type_ref V) { |
||
1000 | TreeTy *NewT = F.add(Old.Root.get(), V); |
||
1001 | return ImmutableSet(Canonicalize ? F.getCanonicalTree(NewT) : NewT); |
||
1002 | } |
||
1003 | |||
1004 | /// remove - Creates a new immutable set that contains all of the values |
||
1005 | /// of the original set with the exception of the specified value. If |
||
1006 | /// the original set did not contain the value, the original set is |
||
1007 | /// returned and no memory is allocated. The time and space complexity |
||
1008 | /// of this operation is logarithmic in the size of the original set. |
||
1009 | /// The memory allocated to represent the set is released when the |
||
1010 | /// factory object that created the set is destroyed. |
||
1011 | [[nodiscard]] ImmutableSet remove(ImmutableSet Old, value_type_ref V) { |
||
1012 | TreeTy *NewT = F.remove(Old.Root.get(), V); |
||
1013 | return ImmutableSet(Canonicalize ? F.getCanonicalTree(NewT) : NewT); |
||
1014 | } |
||
1015 | |||
1016 | BumpPtrAllocator& getAllocator() { return F.getAllocator(); } |
||
1017 | |||
1018 | typename TreeTy::Factory *getTreeFactory() const { |
||
1019 | return const_cast<typename TreeTy::Factory *>(&F); |
||
1020 | } |
||
1021 | }; |
||
1022 | |||
1023 | friend class Factory; |
||
1024 | |||
1025 | /// Returns true if the set contains the specified value. |
||
1026 | bool contains(value_type_ref V) const { |
||
1027 | return Root ? Root->contains(V) : false; |
||
1028 | } |
||
1029 | |||
1030 | bool operator==(const ImmutableSet &RHS) const { |
||
1031 | return Root && RHS.Root ? Root->isEqual(*RHS.Root.get()) : Root == RHS.Root; |
||
1032 | } |
||
1033 | |||
1034 | bool operator!=(const ImmutableSet &RHS) const { |
||
1035 | return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get()) |
||
1036 | : Root != RHS.Root; |
||
1037 | } |
||
1038 | |||
1039 | TreeTy *getRoot() { |
||
1040 | if (Root) { Root->retain(); } |
||
1041 | return Root.get(); |
||
1042 | } |
||
1043 | |||
1044 | TreeTy *getRootWithoutRetain() const { return Root.get(); } |
||
1045 | |||
1046 | /// isEmpty - Return true if the set contains no elements. |
||
1047 | bool isEmpty() const { return !Root; } |
||
1048 | |||
1049 | /// isSingleton - Return true if the set contains exactly one element. |
||
1050 | /// This method runs in constant time. |
||
1051 | bool isSingleton() const { return getHeight() == 1; } |
||
1052 | |||
1053 | //===--------------------------------------------------===// |
||
1054 | // Iterators. |
||
1055 | //===--------------------------------------------------===// |
||
1056 | |||
1057 | using iterator = ImutAVLValueIterator<ImmutableSet>; |
||
1058 | |||
1059 | iterator begin() const { return iterator(Root.get()); } |
||
1060 | iterator end() const { return iterator(); } |
||
1061 | |||
1062 | //===--------------------------------------------------===// |
||
1063 | // Utility methods. |
||
1064 | //===--------------------------------------------------===// |
||
1065 | |||
1066 | unsigned getHeight() const { return Root ? Root->getHeight() : 0; } |
||
1067 | |||
1068 | static void Profile(FoldingSetNodeID &ID, const ImmutableSet &S) { |
||
1069 | ID.AddPointer(S.Root.get()); |
||
1070 | } |
||
1071 | |||
1072 | void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); } |
||
1073 | |||
1074 | //===--------------------------------------------------===// |
||
1075 | // For testing. |
||
1076 | //===--------------------------------------------------===// |
||
1077 | |||
1078 | void validateTree() const { if (Root) Root->validateTree(); } |
||
1079 | }; |
||
1080 | |||
1081 | // NOTE: This may some day replace the current ImmutableSet. |
||
1082 | template <typename ValT, typename ValInfo = ImutContainerInfo<ValT>> |
||
1083 | class ImmutableSetRef { |
||
1084 | public: |
||
1085 | using value_type = typename ValInfo::value_type; |
||
1086 | using value_type_ref = typename ValInfo::value_type_ref; |
||
1087 | using TreeTy = ImutAVLTree<ValInfo>; |
||
1088 | using FactoryTy = typename TreeTy::Factory; |
||
1089 | |||
1090 | private: |
||
1091 | IntrusiveRefCntPtr<TreeTy> Root; |
||
1092 | FactoryTy *Factory; |
||
1093 | |||
1094 | public: |
||
1095 | /// Constructs a set from a pointer to a tree root. In general one |
||
1096 | /// should use a Factory object to create sets instead of directly |
||
1097 | /// invoking the constructor, but there are cases where make this |
||
1098 | /// constructor public is useful. |
||
1099 | ImmutableSetRef(TreeTy *R, FactoryTy *F) : Root(R), Factory(F) {} |
||
1100 | |||
1101 | static ImmutableSetRef getEmptySet(FactoryTy *F) { |
||
1102 | return ImmutableSetRef(0, F); |
||
1103 | } |
||
1104 | |||
1105 | ImmutableSetRef add(value_type_ref V) { |
||
1106 | return ImmutableSetRef(Factory->add(Root.get(), V), Factory); |
||
1107 | } |
||
1108 | |||
1109 | ImmutableSetRef remove(value_type_ref V) { |
||
1110 | return ImmutableSetRef(Factory->remove(Root.get(), V), Factory); |
||
1111 | } |
||
1112 | |||
1113 | /// Returns true if the set contains the specified value. |
||
1114 | bool contains(value_type_ref V) const { |
||
1115 | return Root ? Root->contains(V) : false; |
||
1116 | } |
||
1117 | |||
1118 | ImmutableSet<ValT> asImmutableSet(bool canonicalize = true) const { |
||
1119 | return ImmutableSet<ValT>( |
||
1120 | canonicalize ? Factory->getCanonicalTree(Root.get()) : Root.get()); |
||
1121 | } |
||
1122 | |||
1123 | TreeTy *getRootWithoutRetain() const { return Root.get(); } |
||
1124 | |||
1125 | bool operator==(const ImmutableSetRef &RHS) const { |
||
1126 | return Root && RHS.Root ? Root->isEqual(*RHS.Root.get()) : Root == RHS.Root; |
||
1127 | } |
||
1128 | |||
1129 | bool operator!=(const ImmutableSetRef &RHS) const { |
||
1130 | return Root && RHS.Root ? Root->isNotEqual(*RHS.Root.get()) |
||
1131 | : Root != RHS.Root; |
||
1132 | } |
||
1133 | |||
1134 | /// isEmpty - Return true if the set contains no elements. |
||
1135 | bool isEmpty() const { return !Root; } |
||
1136 | |||
1137 | /// isSingleton - Return true if the set contains exactly one element. |
||
1138 | /// This method runs in constant time. |
||
1139 | bool isSingleton() const { return getHeight() == 1; } |
||
1140 | |||
1141 | //===--------------------------------------------------===// |
||
1142 | // Iterators. |
||
1143 | //===--------------------------------------------------===// |
||
1144 | |||
1145 | using iterator = ImutAVLValueIterator<ImmutableSetRef>; |
||
1146 | |||
1147 | iterator begin() const { return iterator(Root.get()); } |
||
1148 | iterator end() const { return iterator(); } |
||
1149 | |||
1150 | //===--------------------------------------------------===// |
||
1151 | // Utility methods. |
||
1152 | //===--------------------------------------------------===// |
||
1153 | |||
1154 | unsigned getHeight() const { return Root ? Root->getHeight() : 0; } |
||
1155 | |||
1156 | static void Profile(FoldingSetNodeID &ID, const ImmutableSetRef &S) { |
||
1157 | ID.AddPointer(S.Root.get()); |
||
1158 | } |
||
1159 | |||
1160 | void Profile(FoldingSetNodeID &ID) const { return Profile(ID, *this); } |
||
1161 | |||
1162 | //===--------------------------------------------------===// |
||
1163 | // For testing. |
||
1164 | //===--------------------------------------------------===// |
||
1165 | |||
1166 | void validateTree() const { if (Root) Root->validateTree(); } |
||
1167 | }; |
||
1168 | |||
1169 | } // end namespace llvm |
||
1170 | |||
1171 | #endif // LLVM_ADT_IMMUTABLESET_H |