]>
git.ipfire.org Git - thirdparty/squid.git/blob - include/splay.h
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 #ifndef SQUID_INCLUDE_SPLAY_H
10 #define SQUID_INCLUDE_SPLAY_H
16 // private class of Splay. Do not use directly
22 typedef int SPLAYCMP(Value
const &a
, Value
const &b
);
24 SplayNode(const Value
&);
26 mutable SplayNode
<V
> *left
;
27 mutable SplayNode
<V
> *right
;
28 mutable SplayNode
<V
> *visitThreadUp
;
30 SplayNode
<V
> const * start() const;
31 SplayNode
<V
> const * finish() const;
33 SplayNode
<V
> * remove(const Value data
, SPLAYCMP
* compare
);
35 SplayNode
<V
> * insert(Value data
, SPLAYCMP
* compare
);
37 /// look in the splay for data for where compare(data,candidate) == true.
38 /// return NULL if not found, a pointer to the sought data if found.
39 template <class FindValue
> SplayNode
<V
> * splay(const FindValue
&data
, int( * compare
)(FindValue
const &a
, Value
const &b
)) const;
43 class SplayConstIterator
;
53 typedef int SPLAYCMP(Value
const &a
, Value
const &b
);
54 typedef void SPLAYFREE(Value
&);
55 typedef SplayIterator
<V
> iterator
;
56 typedef const SplayConstIterator
<V
> const_iterator
;
58 static void DefaultFree(Value
&v
) { delete v
; }
60 Splay():head(nullptr), elements (0) {}
62 template <class FindValue
> Value
const *find (FindValue
const &, int( * compare
)(FindValue
const &a
, Value
const &b
)) const;
64 /// If the given value matches a stored one, returns that matching value.
65 /// Otherwise, stores the given unique value and returns nil.
66 const Value
*insert(const Value
&, SPLAYCMP
*);
68 void remove(Value
const &, SPLAYCMP
*compare
);
70 void destroy(SPLAYFREE
* = DefaultFree
);
72 SplayNode
<V
> const * start() const;
74 SplayNode
<V
> const * finish() const;
78 bool empty() const { return size() == 0; }
80 const_iterator
begin() const;
82 const_iterator
end() const;
84 /// left-to-right visit of all stored Values
85 template <typename ValueVisitor
> void visit(ValueVisitor
&) const;
88 /// left-to-right walk through all nodes
89 template <typename NodeVisitor
> void visitEach(NodeVisitor
&) const;
91 mutable SplayNode
<V
> * head
;
95 extern int splayLastResult
;
98 SplayNode
<V
>::SplayNode(const Value
&someData
): data(someData
), left(nullptr), right(nullptr), visitThreadUp(nullptr) {}
102 SplayNode
<V
>::start() const
112 SplayNode
<V
>::finish() const
122 SplayNode
<V
>::remove(Value
const dataToRemove
, SPLAYCMP
* compare
)
124 SplayNode
<V
> *result
= splay(dataToRemove
, compare
);
126 if (splayLastResult
== 0) { /* found it */
127 SplayNode
<V
> *newTop
;
129 if (result
->left
== nullptr) {
130 newTop
= result
->right
;
132 newTop
= result
->left
->splay(dataToRemove
, compare
);
134 newTop
->right
= result
->right
;
135 result
->right
= nullptr;
142 return result
; /* It wasn't there */
147 SplayNode
<V
>::insert(Value dataToInsert
, SPLAYCMP
* compare
)
149 /* create node to insert */
150 SplayNode
<V
> *newNode
= new SplayNode
<V
>(dataToInsert
);
151 SplayNode
<V
> *newTop
= splay(dataToInsert
, compare
);
153 if (splayLastResult
< 0) {
154 newNode
->left
= newTop
->left
;
155 newNode
->right
= newTop
;
156 newTop
->left
= nullptr;
158 } else if (splayLastResult
> 0) {
159 newNode
->right
= newTop
->right
;
160 newNode
->left
= newTop
;
161 newTop
->right
= nullptr;
164 /* duplicate entry */
171 template<class FindValue
>
173 SplayNode
<V
>::splay(FindValue
const &dataToFind
, int( * compare
)(FindValue
const &a
, Value
const &b
)) const
175 Value temp
= Value();
176 SplayNode
<V
> N(temp
);
180 N
.left
= N
.right
= nullptr;
183 SplayNode
<V
> *top
= const_cast<SplayNode
<V
> *>(this);
186 splayLastResult
= compare(dataToFind
, top
->data
);
188 if (splayLastResult
< 0) {
189 if (top
->left
== nullptr)
192 if ((splayLastResult
= compare(dataToFind
, top
->left
->data
)) < 0) {
193 y
= top
->left
; /* rotate right */
194 top
->left
= y
->right
;
198 if (top
->left
== nullptr)
202 r
->left
= top
; /* link right */
205 } else if (splayLastResult
> 0) {
206 if (top
->right
== nullptr)
209 if ((splayLastResult
= compare(dataToFind
, top
->right
->data
)) > 0) {
210 y
= top
->right
; /* rotate left */
211 top
->right
= y
->left
;
215 if (top
->right
== nullptr)
219 l
->right
= top
; /* link left */
227 l
->right
= top
->left
; /* assemble */
228 r
->left
= top
->right
;
235 template <class Visitor
>
237 Splay
<V
>::visitEach(Visitor
&visitor
) const
239 // In-order walk through tree using modified Morris Traversal: To avoid a
240 // leftover thread up (and, therefore, a fatal loop in the tree) due to a
241 // visitor exception, we use an extra pointer visitThreadUp instead of
242 // manipulating the right child link and interfering with other methods
243 // that use that link.
244 // This also helps to distinguish between up and down movements, eliminating
245 // the need to descent into left subtree a second time after traversing the
246 // thread to find the loop and remove the temporary thread.
252 auto movedUp
= false;
253 cur
->visitThreadUp
= nullptr;
256 if (!cur
->left
|| movedUp
) {
257 // no (unvisited) left subtree, so handle current node ...
258 const auto old
= cur
;
260 // ... and descent into right subtree
264 else if (cur
->visitThreadUp
) {
265 // ... or back up the thread
266 cur
= cur
->visitThreadUp
;
273 // old may be destroyed here
275 // first descent into left subtree
277 // find right-most child in left tree
278 auto rmc
= cur
->left
;
280 rmc
->visitThreadUp
= nullptr; // cleanup old threads on the way
283 // create thread up back to cur
284 rmc
->visitThreadUp
= cur
;
286 // finally descent into left subtree
294 template <class Visitor
>
296 Splay
<V
>::visit(Visitor
&visitor
) const
298 const auto internalVisitor
= [&visitor
](const SplayNode
<V
> *node
) { visitor(node
->data
); };
299 visitEach(internalVisitor
);
303 template <class FindValue
>
304 typename Splay
<V
>::Value
const *
305 Splay
<V
>::find (FindValue
const &value
, int( * compare
)(FindValue
const &a
, Value
const &b
)) const
310 head
= head
->splay(value
, compare
);
312 if (splayLastResult
!= 0)
319 typename Splay
<V
>::Value
const *
320 Splay
<V
>::insert(Value
const &value
, SPLAYCMP
*compare
)
322 if (const auto similarValue
= find(value
, compare
))
323 return similarValue
; // do not insert duplicates
326 head
= new SplayNode
<V
>(value
);
328 head
= head
->insert(value
, compare
);
331 return nullptr; // no duplicates found
336 Splay
<V
>::remove(Value
const &value
, SPLAYCMP
*compare
)
338 // also catches the head==NULL case
339 if (find(value
, compare
) == nullptr)
342 head
= head
->remove(value
, compare
);
349 Splay
<V
>:: start() const
352 return head
->start();
359 Splay
<V
>:: finish() const
362 return head
->finish();
369 Splay
<V
>:: destroy(SPLAYFREE
*free_func
)
371 const auto destroyer
= [free_func
](SplayNode
<V
> *node
) { free_func(node
->data
); delete node
; };
372 visitEach(destroyer
);
381 Splay
<V
>::size() const
387 const SplayConstIterator
<V
>
388 Splay
<V
>::begin() const
390 return const_iterator(head
);
394 const SplayConstIterator
<V
>
395 Splay
<V
>::end() const
397 return const_iterator(nullptr);
400 // XXX: This does not seem to iterate the whole thing in some cases.
402 class SplayConstIterator
406 typedef const V value_type
;
407 SplayConstIterator (SplayNode
<V
> *aNode
);
408 bool operator == (SplayConstIterator
const &right
) const;
409 SplayConstIterator
operator ++ (int dummy
);
410 SplayConstIterator
&operator ++ ();
411 V
const & operator * () const;
415 void addLeftPath(SplayNode
<V
> *aNode
);
416 void init(SplayNode
<V
> *);
417 std::stack
<SplayNode
<V
> *> toVisit
;
421 SplayConstIterator
<V
>::SplayConstIterator (SplayNode
<V
> *aNode
)
428 SplayConstIterator
<V
>::operator == (SplayConstIterator
const &right
) const
430 if (toVisit
.empty() && right
.toVisit
.empty())
432 if (!toVisit
.empty() && !right
.toVisit
.empty())
433 return toVisit
.top() == right
.toVisit
.top();
434 // only one of the two is empty
439 SplayConstIterator
<V
> &
440 SplayConstIterator
<V
>::operator ++ ()
447 SplayConstIterator
<V
>
448 SplayConstIterator
<V
>::operator ++ (int)
450 SplayConstIterator
<V
> result
= *this;
455 /* advance is simple enough:
456 * if the stack is empty, we're done.
457 * otherwise, pop the last visited node
458 * then, pop the next node to visit
459 * if that has a right child, add it and it's
461 * then add the node back.
465 SplayConstIterator
<V
>::advance()
476 SplayNode
<V
> *currentNode
= toVisit
.top();
479 addLeftPath(currentNode
->right
);
481 toVisit
.push(currentNode
);
486 SplayConstIterator
<V
>::addLeftPath(SplayNode
<V
> *aNode
)
488 if (aNode
== nullptr)
494 } while (aNode
!= nullptr);
499 SplayConstIterator
<V
>::init(SplayNode
<V
> *head
)
506 SplayConstIterator
<V
>::operator * () const
508 /* can't dereference when past the end */
510 if (toVisit
.size() == 0)
511 fatal ("Attempt to dereference SplayConstIterator past-the-end\n");
513 return toVisit
.top()->data
;
516 #endif /* SQUID_INCLUDE_SPLAY_H */