splay.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9#ifndef SQUID_SPLAY_H
10#define SQUID_SPLAY_H
11
12#include "fatal.h"
13#include <cstddef>
14#include <stack>
15
16// private class of Splay. Do not use directly
17template <class V>
19{
20public:
21 typedef V Value;
22 typedef int SPLAYCMP(Value const &a, Value const &b);
23
24 SplayNode<V> (Value const &);
29
30 SplayNode<V> const * start() const;
31 SplayNode<V> const * finish() const;
32
33 SplayNode<V> * remove(const Value data, SPLAYCMP * compare);
34
36
39 template <class FindValue> SplayNode<V> * splay(const FindValue &data, int( * compare)(FindValue const &a, Value const &b)) const;
40};
41
42template <class V>
44
45template <class V>
47
48template <class V>
49class Splay
50{
51public:
52 typedef V Value;
53 typedef int SPLAYCMP(Value const &a, Value const &b);
54 typedef void SPLAYFREE(Value &);
57
58 static void DefaultFree(Value &v) { delete v; }
59
60 Splay():head(nullptr), elements (0) {}
61
62 template <class FindValue> Value const *find (FindValue const &, int( * compare)(FindValue const &a, Value const &b)) const;
63
64 void insert(Value const &, SPLAYCMP *compare);
65
66 void remove(Value const &, SPLAYCMP *compare);
67
69
70 SplayNode<V> const * start() const;
71
72 SplayNode<V> const * finish() const;
73
74 size_t size() const;
75
76 bool empty() const { return size() == 0; }
77
79
81
83 template <typename ValueVisitor> void visit(ValueVisitor &) const;
84
85private:
87 template <typename NodeVisitor> void visitEach(NodeVisitor &) const;
88
89 mutable SplayNode<V> * head;
90 size_t elements;
91};
92
94
95template<class V>
96SplayNode<V>::SplayNode(const Value &someData): data(someData), left(nullptr), right(nullptr), visitThreadUp(nullptr) {}
97
98template<class V>
99SplayNode<V> const *
101{
102 auto cur = this;
103 while (cur->left)
104 cur = cur->left;
105 return cur;
106}
107
108template<class V>
109SplayNode<V> const *
111{
112 auto cur = this;
113 while (cur->right)
114 cur = cur->right;
115 return cur;
116}
117
118template<class V>
120SplayNode<V>::remove(Value const dataToRemove, SPLAYCMP * compare)
121{
122 SplayNode<V> *result = splay(dataToRemove, compare);
123
124 if (splayLastResult == 0) { /* found it */
125 SplayNode<V> *newTop;
126
127 if (result->left == nullptr) {
128 newTop = result->right;
129 } else {
130 newTop = result->left->splay(dataToRemove, compare);
131 /* temporary */
132 newTop->right = result->right;
133 result->right = nullptr;
134 }
135
136 delete result;
137 return newTop;
138 }
139
140 return result; /* It wasn't there */
141}
142
143template<class V>
145SplayNode<V>::insert(Value dataToInsert, SPLAYCMP * compare)
146{
147 /* create node to insert */
148 SplayNode<V> *newNode = new SplayNode<V>(dataToInsert);
149 SplayNode<V> *newTop = splay(dataToInsert, compare);
150
151 if (splayLastResult < 0) {
152 newNode->left = newTop->left;
153 newNode->right = newTop;
154 newTop->left = nullptr;
155 return newNode;
156 } else if (splayLastResult > 0) {
157 newNode->right = newTop->right;
158 newNode->left = newTop;
159 newTop->right = nullptr;
160 return newNode;
161 } else {
162 /* duplicate entry */
163 delete newNode;
164 return newTop;
165 }
166}
167
168template<class V>
169template<class FindValue>
171SplayNode<V>::splay(FindValue const &dataToFind, int( * compare)(FindValue const &a, Value const &b)) const
172{
173 Value temp = Value();
174 SplayNode<V> N(temp);
175 SplayNode<V> *l;
176 SplayNode<V> *r;
177 SplayNode<V> *y;
178 N.left = N.right = nullptr;
179 l = r = &N;
180
181 SplayNode<V> *top = const_cast<SplayNode<V> *>(this);
182
183 for (;;) {
184 splayLastResult = compare(dataToFind, top->data);
185
186 if (splayLastResult < 0) {
187 if (top->left == nullptr)
188 break;
189
190 if ((splayLastResult = compare(dataToFind, top->left->data)) < 0) {
191 y = top->left; /* rotate right */
192 top->left = y->right;
193 y->right = top;
194 top = y;
195
196 if (top->left == nullptr)
197 break;
198 }
199
200 r->left = top; /* link right */
201 r = top;
202 top = top->left;
203 } else if (splayLastResult > 0) {
204 if (top->right == nullptr)
205 break;
206
207 if ((splayLastResult = compare(dataToFind, top->right->data)) > 0) {
208 y = top->right; /* rotate left */
209 top->right = y->left;
210 y->left = top;
211 top = y;
212
213 if (top->right == nullptr)
214 break;
215 }
216
217 l->right = top; /* link left */
218 l = top;
219 top = top->right;
220 } else {
221 break;
222 }
223 }
224
225 l->right = top->left; /* assemble */
226 r->left = top->right;
227 top->left = N.right;
228 top->right = N.left;
229 return top;
230}
231
232template <class V>
233template <class Visitor>
234void
235Splay<V>::visitEach(Visitor &visitor) const
236{
237 // In-order walk through tree using modified Morris Traversal: To avoid a
238 // leftover thread up (and, therefore, a fatal loop in the tree) due to a
239 // visitor exception, we use an extra pointer visitThreadUp instead of
240 // manipulating the right child link and interfering with other methods
241 // that use that link.
242 // This also helps to distinguish between up and down movements, eliminating
243 // the need to descent into left subtree a second time after traversing the
244 // thread to find the loop and remove the temporary thread.
245
246 if (!head)
247 return;
248
249 auto cur = head;
250 auto movedUp = false;
251 cur->visitThreadUp = nullptr;
252
253 while (cur) {
254 if (!cur->left || movedUp) {
255 // no (unvisited) left subtree, so handle current node ...
256 const auto old = cur;
257 if (cur->right) {
258 // ... and descent into right subtree
259 cur = cur->right;
260 movedUp = false;
261 }
262 else if (cur->visitThreadUp) {
263 // ... or back up the thread
264 cur = cur->visitThreadUp;
265 movedUp = true;
266 } else {
267 // end of traversal
268 cur = nullptr;
269 }
270 visitor(old);
271 // old may be destroyed here
272 } else {
273 // first descent into left subtree
274
275 // find right-most child in left tree
276 auto rmc = cur->left;
277 while (rmc->right) {
278 rmc->visitThreadUp = nullptr; // cleanup old threads on the way
279 rmc = rmc->right;
280 }
281 // create thread up back to cur
282 rmc->visitThreadUp = cur;
283
284 // finally descent into left subtree
285 cur = cur->left;
286 movedUp = false;
287 }
288 }
289}
290
291template <class V>
292template <class Visitor>
293void
294Splay<V>::visit(Visitor &visitor) const
295{
296 const auto internalVisitor = [&visitor](const SplayNode<V> *node) { visitor(node->data); };
297 visitEach(internalVisitor);
298}
299
300template <class V>
301template <class FindValue>
302typename Splay<V>::Value const *
303Splay<V>::find (FindValue const &value, int( * compare)(FindValue const &a, Value const &b)) const
304{
305 if (head == nullptr)
306 return nullptr;
307
308 head = head->splay(value, compare);
309
310 if (splayLastResult != 0)
311 return nullptr;
312
313 return &head->data;
314}
315
316template <class V>
317void
318Splay<V>::insert(Value const &value, SPLAYCMP *compare)
319{
320 if (find(value, compare) != nullptr) // ignore duplicates
321 return;
322
323 if (head == nullptr)
324 head = new SplayNode<V>(value);
325 else
326 head = head->insert(value, compare);
327 ++elements;
328}
329
330template <class V>
331void
332Splay<V>::remove(Value const &value, SPLAYCMP *compare)
333{
334 // also catches the head==NULL case
335 if (find(value, compare) == nullptr)
336 return;
337
338 head = head->remove(value, compare);
339
340 --elements;
341}
342
343template <class V>
344SplayNode<V> const *
346{
347 if (head)
348 return head->start();
349
350 return nullptr;
351}
352
353template <class V>
354SplayNode<V> const *
356{
357 if (head)
358 return head->finish();
359
360 return nullptr;
361}
362
363template <class V>
364void
365Splay<V>:: destroy(SPLAYFREE *free_func)
366{
367 const auto destroyer = [free_func](SplayNode<V> *node) { free_func(node->data); delete node; };
368 visitEach(destroyer);
369
370 head = nullptr;
371
372 elements = 0;
373}
374
375template <class V>
376size_t
378{
379 return elements;
380}
381
382template <class V>
385{
386 return const_iterator(head);
387}
388
389template <class V>
392{
393 return const_iterator(nullptr);
394}
395
396// XXX: This does not seem to iterate the whole thing in some cases.
397template <class V>
399{
400
401public:
402 typedef const V value_type;
404 bool operator == (SplayConstIterator const &right) const;
407 V const & operator * () const;
408
409private:
410 void advance();
411 void addLeftPath(SplayNode<V> *aNode);
412 void init(SplayNode<V> *);
413 std::stack<SplayNode<V> *> toVisit;
414};
415
416template <class V>
418{
419 init(aNode);
420}
421
422template <class V>
423bool
425{
426 if (toVisit.empty() && right.toVisit.empty())
427 return true;
428 if (!toVisit.empty() && !right.toVisit.empty())
429 return toVisit.top() == right.toVisit.top();
430 // only one of the two is empty
431 return false;
432}
433
434template <class V>
437{
438 advance();
439 return *this;
440}
441
442template <class V>
445{
446 SplayConstIterator<V> result = *this;
447 advance();
448 return result;
449}
450
451/* advance is simple enough:
452* if the stack is empty, we're done.
453* otherwise, pop the last visited node
454* then, pop the next node to visit
455* if that has a right child, add it and it's
456* left-to-end path.
457* then add the node back.
458*/
459template <class V>
460void
462{
463 if (toVisit.empty())
464 return;
465
466 toVisit.pop();
467
468 if (toVisit.empty())
469 return;
470
471 // not empty
472 SplayNode<V> *currentNode = toVisit.top();
473 toVisit.pop();
474
475 addLeftPath(currentNode->right);
476
477 toVisit.push(currentNode);
478}
479
480template <class V>
481void
483{
484 if (aNode == nullptr)
485 return;
486
487 do {
488 toVisit.push(aNode);
489 aNode = aNode->left;
490 } while (aNode != nullptr);
491}
492
493template <class V>
494void
496{
497 addLeftPath(head);
498}
499
500template <class V>
501V const &
503{
504 /* can't dereference when past the end */
505
506 if (toVisit.size() == 0)
507 fatal ("Attempt to dereference SplayConstIterator past-the-end\n");
508
509 return toVisit.top()->data;
510}
511
512#endif /* SQUID_SPLAY_H */
513
int cur
Definition: ModDevPoll.cc:74
squidaio_request_t * head
Definition: aiops.cc:127
SplayConstIterator(SplayNode< V > *aNode)
Definition: splay.h:417
V const & operator*() const
Definition: splay.h:502
void advance()
Definition: splay.h:461
std::stack< SplayNode< V > * > toVisit
Definition: splay.h:413
const V value_type
Definition: splay.h:402
SplayConstIterator & operator++()
Definition: splay.h:436
void addLeftPath(SplayNode< V > *aNode)
Definition: splay.h:482
bool operator==(SplayConstIterator const &right) const
Definition: splay.h:424
void init(SplayNode< V > *)
Definition: splay.h:495
Value data
Definition: splay.h:25
SplayNode< V > * right
Definition: splay.h:27
SplayNode< V > * visitThreadUp
Definition: splay.h:28
SplayNode< V > * splay(const FindValue &data, int(*compare)(FindValue const &a, Value const &b)) const
Definition: splay.h:171
SplayNode< V > * insert(Value data, SPLAYCMP *compare)
Definition: splay.h:145
SplayNode< V > * left
Definition: splay.h:26
SplayNode< V > * remove(const Value data, SPLAYCMP *compare)
Definition: splay.h:120
int SPLAYCMP(Value const &a, Value const &b)
Definition: splay.h:22
SplayNode< V > const * finish() const
Definition: splay.h:110
V Value
Definition: splay.h:21
SplayNode(Value const &)
Definition: splay.h:96
SplayNode< V > const * start() const
Definition: splay.h:100
Definition: splay.h:50
const_iterator begin() const
Definition: splay.h:384
SplayNode< V > * head
Definition: splay.h:89
size_t elements
Definition: splay.h:90
const SplayConstIterator< V > const_iterator
Definition: splay.h:56
SplayIterator< V > iterator
Definition: splay.h:55
Value const * find(FindValue const &, int(*compare)(FindValue const &a, Value const &b)) const
static void DefaultFree(Value &v)
Definition: splay.h:58
const_iterator end() const
Definition: splay.h:391
void remove(Value const &, SPLAYCMP *compare)
Definition: splay.h:332
bool empty() const
Definition: splay.h:76
SplayNode< V > const * start() const
Definition: splay.h:345
void visitEach(NodeVisitor &) const
left-to-right walk through all nodes
void insert(Value const &, SPLAYCMP *compare)
Definition: splay.h:318
SplayNode< V > const * finish() const
Definition: splay.h:355
size_t size() const
Definition: splay.h:377
int SPLAYCMP(Value const &a, Value const &b)
Definition: splay.h:53
void visit(ValueVisitor &) const
left-to-right visit of all stored Values
void SPLAYFREE(Value &)
Definition: splay.h:54
void destroy(SPLAYFREE *=DefaultFree)
Definition: splay.h:365
Splay()
Definition: splay.h:60
V Value
Definition: splay.h:52
void fatal(const char *message)
Definition: fatal.cc:28
SQUIDCEXTERN int splayLastResult
Definition: splay.h:93
#define SQUIDCEXTERN
Definition: squid.h:21
Definition: parse.c:104
Comm::AcceptLimiter dummy
Definition: stub_libcomm.cc:16

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors