]> git.ipfire.org Git - thirdparty/squid.git/blame - include/splay.h
Upgrade ACLFilledChecklist::request to smart Pointer (#1501)
[thirdparty/squid.git] / include / splay.h
CommitLineData
5c193dec 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
5c193dec
AJ
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
b5638623 9#ifndef SQUID_SPLAY_H
10#define SQUID_SPLAY_H
3c01c392 11
cfb88efb 12#include "fatal.h"
a7b75c64 13#include <cstddef>
cfb88efb 14#include <stack>
29b17d63 15
fb3eae94 16// private class of Splay. Do not use directly
b67e2c8c 17template <class V>
42a503bd 18class SplayNode
19{
42a503bd 20public:
b67e2c8c 21 typedef V Value;
29b17d63 22 typedef int SPLAYCMP(Value const &a, Value const &b);
23 typedef void SPLAYFREE(Value &);
24 typedef void SPLAYWALKEE(Value const & nodedata, void *state);
00d77d6b 25 static void DefaultFree (Value &aValue) {delete aValue;}
42a503bd 26
2bcafc95 27 SplayNode<V> (Value const &);
29b17d63 28 Value data;
29 mutable SplayNode<V> *left;
30 mutable SplayNode<V> *right;
fb3eae94 31 void destroy(SPLAYFREE * = DefaultFree);
4c50505b 32 SplayNode<V> const * start() const;
ccd33084 33 SplayNode<V> const * finish() const;
42a503bd 34
6ca34f6f 35 SplayNode<V> * remove(const Value data, SPLAYCMP * compare);
42a503bd 36
29b17d63 37 SplayNode<V> * insert(Value data, SPLAYCMP * compare);
42a503bd 38
fb3eae94
FC
39 /// look in the splay for data for where compare(data,candidate) == true.
40 /// return NULL if not found, a pointer to the sought data if found.
b001e822 41 template <class FindValue> SplayNode<V> * splay(const FindValue &data, int( * compare)(FindValue const &a, Value const &b)) const;
97754f5a
AR
42
43 /// recursively visit left nodes, this node, and then right nodes
44 template <class Visitor> void visit(Visitor &v) const;
b67e2c8c 45};
46
29b17d63 47typedef SplayNode<void *> splayNode;
48
49template <class V>
b8bad68c 50class SplayConstIterator;
51
52template <class V>
ccd33084 53class SplayIterator;
54
55template <class V>
42a503bd 56class Splay
57{
42a503bd 58public:
29b17d63 59 typedef V Value;
60 typedef int SPLAYCMP(Value const &a, Value const &b);
42a503bd 61 typedef void SPLAYFREE(Value &);
b8bad68c 62 typedef SplayIterator<V> iterator;
63 typedef const SplayConstIterator<V> const_iterator;
aee3523a 64 Splay():head(nullptr), elements (0) {}
42a503bd 65
b001e822 66 template <class FindValue> Value const *find (FindValue const &, int( * compare)(FindValue const &a, Value const &b)) const;
fb3eae94 67
0353e724 68 void insert(Value const &, SPLAYCMP *compare);
42a503bd 69
6ca34f6f 70 void remove(Value const &, SPLAYCMP *compare);
42a503bd 71
fb3eae94 72 void destroy(SPLAYFREE * = SplayNode<V>::DefaultFree);
42a503bd 73
4c50505b 74 SplayNode<V> const * start() const;
42a503bd 75
ccd33084 76 SplayNode<V> const * finish() const;
42a503bd 77
78 size_t size() const;
79
4a0199ee 80 bool empty() const { return size() == 0; }
fb3eae94 81
b8bad68c 82 const_iterator begin() const;
83
84 const_iterator end() const;
85
97754f5a
AR
86 /// recursively visit all nodes, in left-to-right order
87 template <class Visitor> void visit(Visitor &v) const;
88
f5dc4237
FC
89private:
90 mutable SplayNode<V> * head;
e9505c9b 91 size_t elements;
29b17d63 92};
b67e2c8c 93
b67e2c8c 94SQUIDCEXTERN int splayLastResult;
95
29b17d63 96template<class V>
aee3523a 97SplayNode<V>::SplayNode (Value const &someData) : data(someData), left(nullptr), right (nullptr) {}
2bcafc95 98
4c50505b 99template<class V>
100SplayNode<V> const *
101SplayNode<V>::start() const
102{
e45bad43 103 if (left)
42a503bd 104 return left->start();
105
106 return this;
107}
108
109template<class V>
110SplayNode<V> const *
ccd33084 111SplayNode<V>::finish() const
42a503bd 112{
e45bad43 113 if (right)
ccd33084 114 return right->finish();
42a503bd 115
4c50505b 116 return this;
117}
118
29b17d63 119template<class V>
120void
121SplayNode<V>::destroy(SPLAYFREE * free_func)
122{
29b17d63 123 if (left)
42a503bd 124 left->destroy(free_func);
125
29b17d63 126 if (right)
42a503bd 127 right->destroy(free_func);
128
29b17d63 129 free_func(data);
42a503bd 130
29b17d63 131 delete this;
132}
133
134template<class V>
135SplayNode<V> *
6ca34f6f 136SplayNode<V>::remove(Value const dataToRemove, SPLAYCMP * compare)
29b17d63 137{
626e1f97 138 SplayNode<V> *result = splay(dataToRemove, compare);
42a503bd 139
f53969cc 140 if (splayLastResult == 0) { /* found it */
42a503bd 141 SplayNode<V> *newTop;
142
aee3523a 143 if (result->left == nullptr) {
42a503bd 144 newTop = result->right;
145 } else {
146 newTop = result->left->splay(dataToRemove, compare);
147 /* temporary */
148 newTop->right = result->right;
aee3523a 149 result->right = nullptr;
42a503bd 150 }
151
152 delete result;
153 return newTop;
29b17d63 154 }
42a503bd 155
f53969cc 156 return result; /* It wasn't there */
29b17d63 157}
b67e2c8c 158
29b17d63 159template<class V>
160SplayNode<V> *
626e1f97 161SplayNode<V>::insert(Value dataToInsert, SPLAYCMP * compare)
29b17d63 162{
163 /* create node to insert */
2bcafc95 164 SplayNode<V> *newNode = new SplayNode<V>(dataToInsert);
626e1f97 165 SplayNode<V> *newTop = splay(dataToInsert, compare);
42a503bd 166
29b17d63 167 if (splayLastResult < 0) {
42a503bd 168 newNode->left = newTop->left;
169 newNode->right = newTop;
aee3523a 170 newTop->left = nullptr;
42a503bd 171 return newNode;
29b17d63 172 } else if (splayLastResult > 0) {
42a503bd 173 newNode->right = newTop->right;
174 newNode->left = newTop;
aee3523a 175 newTop->right = nullptr;
42a503bd 176 return newNode;
29b17d63 177 } else {
42a503bd 178 /* duplicate entry */
179 delete newNode;
180 return newTop;
29b17d63 181 }
182}
183
184template<class V>
b001e822 185template<class FindValue>
29b17d63 186SplayNode<V> *
b001e822 187SplayNode<V>::splay(FindValue const &dataToFind, int( * compare)(FindValue const &a, Value const &b)) const
29b17d63 188{
b001e822 189 Value temp = Value();
190 SplayNode<V> N(temp);
29b17d63 191 SplayNode<V> *l;
192 SplayNode<V> *r;
193 SplayNode<V> *y;
aee3523a 194 N.left = N.right = nullptr;
29b17d63 195 l = r = &N;
196
197 SplayNode<V> *top = const_cast<SplayNode<V> *>(this);
42a503bd 198
29b17d63 199 for (;;) {
42a503bd 200 splayLastResult = compare(dataToFind, top->data);
201
202 if (splayLastResult < 0) {
aee3523a 203 if (top->left == nullptr)
42a503bd 204 break;
205
206 if ((splayLastResult = compare(dataToFind, top->left->data)) < 0) {
f53969cc 207 y = top->left; /* rotate right */
42a503bd 208 top->left = y->right;
209 y->right = top;
210 top = y;
211
aee3523a 212 if (top->left == nullptr)
42a503bd 213 break;
214 }
215
f53969cc 216 r->left = top; /* link right */
42a503bd 217 r = top;
218 top = top->left;
219 } else if (splayLastResult > 0) {
aee3523a 220 if (top->right == nullptr)
42a503bd 221 break;
222
223 if ((splayLastResult = compare(dataToFind, top->right->data)) > 0) {
f53969cc 224 y = top->right; /* rotate left */
42a503bd 225 top->right = y->left;
226 y->left = top;
227 top = y;
228
aee3523a 229 if (top->right == nullptr)
42a503bd 230 break;
231 }
232
f53969cc 233 l->right = top; /* link left */
42a503bd 234 l = top;
235 top = top->right;
236 } else {
237 break;
238 }
29b17d63 239 }
42a503bd 240
f53969cc 241 l->right = top->left; /* assemble */
29b17d63 242 r->left = top->right;
243 top->left = N.right;
244 top->right = N.left;
245 return top;
246}
247
97754f5a
AR
248template <class V>
249template <class Visitor>
250void
2da4bfe6
A
251SplayNode<V>::visit(Visitor &visitor) const
252{
97754f5a
AR
253 if (left)
254 left->visit(visitor);
255 visitor(data);
256 if (right)
257 right->visit(visitor);
258}
259
260template <class V>
261template <class Visitor>
262void
2da4bfe6
A
263Splay<V>::visit(Visitor &visitor) const
264{
97754f5a
AR
265 if (head)
266 head->visit(visitor);
267}
268
29b17d63 269template <class V>
b001e822 270template <class FindValue>
29b17d63 271typename Splay<V>::Value const *
b001e822 272Splay<V>::find (FindValue const &value, int( * compare)(FindValue const &a, Value const &b)) const
29b17d63 273{
aee3523a
AR
274 if (head == nullptr)
275 return nullptr;
e45bad43 276
29b17d63 277 head = head->splay(value, compare);
42a503bd 278
29b17d63 279 if (splayLastResult != 0)
aee3523a 280 return nullptr;
42a503bd 281
29b17d63 282 return &head->data;
283}
b67e2c8c 284
0353e724 285template <class V>
286void
287Splay<V>::insert(Value const &value, SPLAYCMP *compare)
288{
aee3523a 289 if (find(value, compare) != nullptr) // ignore duplicates
8456681e
AJ
290 return;
291
aee3523a 292 if (head == nullptr)
006b562c
FC
293 head = new SplayNode<V>(value);
294 else
295 head = head->insert(value, compare);
0353e724 296 ++elements;
297}
298
299template <class V>
300void
6ca34f6f 301Splay<V>::remove(Value const &value, SPLAYCMP *compare)
0353e724 302{
b7cfa5b3 303 // also catches the head==NULL case
aee3523a 304 if (find(value, compare) == nullptr)
b7cfa5b3 305 return;
42a503bd 306
6ca34f6f 307 head = head->remove(value, compare);
42a503bd 308
0353e724 309 --elements;
310}
311
4c50505b 312template <class V>
42a503bd 313SplayNode<V> const *
314Splay<V>:: start() const
315{
316 if (head)
317 return head->start();
318
aee3523a 319 return nullptr;
42a503bd 320}
321
322template <class V>
323SplayNode<V> const *
ccd33084 324Splay<V>:: finish() const
42a503bd 325{
4c50505b 326 if (head)
ccd33084 327 return head->finish();
42a503bd 328
aee3523a 329 return nullptr;
4c50505b 330}
331
42a503bd 332template <class V>
333void
334Splay<V>:: destroy(SPLAYFREE *free_func)
335{
336 if (head)
337 head->destroy(free_func);
338
aee3523a 339 head = nullptr;
42a503bd 340
341 elements = 0;
342}
343
344template <class V>
345size_t
346Splay<V>::size() const
347{
348 return elements;
349}
350
b8bad68c 351template <class V>
411c6ea3 352const SplayConstIterator<V>
b8bad68c 353Splay<V>::begin() const
354{
355 return const_iterator(head);
356}
357
358template <class V>
411c6ea3 359const SplayConstIterator<V>
b8bad68c 360Splay<V>::end() const
361{
aee3523a 362 return const_iterator(nullptr);
b8bad68c 363}
364
97754f5a 365// XXX: This does not seem to iterate the whole thing in some cases.
b8bad68c 366template <class V>
b8bad68c 367class SplayConstIterator
368{
369
370public:
371 typedef const V value_type;
372 SplayConstIterator (SplayNode<V> *aNode);
373 bool operator == (SplayConstIterator const &right) const;
374 SplayConstIterator operator ++ (int dummy);
375 SplayConstIterator &operator ++ ();
376 V const & operator * () const;
377
378private:
379 void advance();
380 void addLeftPath(SplayNode<V> *aNode);
381 void init(SplayNode<V> *);
cfb88efb 382 std::stack<SplayNode<V> *> toVisit;
b8bad68c 383};
384
385template <class V>
386SplayConstIterator<V>::SplayConstIterator (SplayNode<V> *aNode)
387{
388 init(aNode);
389}
390
391template <class V>
392bool
393SplayConstIterator<V>::operator == (SplayConstIterator const &right) const
394{
cfb88efb
AR
395 if (toVisit.empty() && right.toVisit.empty())
396 return true;
397 if (!toVisit.empty() && !right.toVisit.empty())
398 return toVisit.top() == right.toVisit.top();
399 // only one of the two is empty
400 return false;
b8bad68c 401}
402
403template <class V>
404SplayConstIterator<V> &
405SplayConstIterator<V>::operator ++ ()
406{
407 advance();
408 return *this;
409}
410
411template <class V>
412SplayConstIterator<V>
8b082ed9 413SplayConstIterator<V>::operator ++ (int)
b8bad68c 414{
415 SplayConstIterator<V> result = *this;
416 advance();
417 return result;
418}
419
420/* advance is simple enough:
421* if the stack is empty, we're done.
422* otherwise, pop the last visited node
423* then, pop the next node to visit
424* if that has a right child, add it and it's
425* left-to-end path.
426* then add the node back.
427*/
428template <class V>
429void
430SplayConstIterator<V>::advance()
431{
cfb88efb 432 if (toVisit.empty())
b8bad68c 433 return;
434
435 toVisit.pop();
436
cfb88efb 437 if (toVisit.empty())
b8bad68c 438 return;
439
cfb88efb
AR
440 // not empty
441 SplayNode<V> *currentNode = toVisit.top();
442 toVisit.pop();
b8bad68c 443
444 addLeftPath(currentNode->right);
445
cfb88efb 446 toVisit.push(currentNode);
b8bad68c 447}
448
449template <class V>
450void
451SplayConstIterator<V>::addLeftPath(SplayNode<V> *aNode)
452{
aee3523a 453 if (aNode == nullptr)
b8bad68c 454 return;
455
456 do {
cfb88efb 457 toVisit.push(aNode);
b8bad68c 458 aNode = aNode->left;
aee3523a 459 } while (aNode != nullptr);
b8bad68c 460}
461
462template <class V>
463void
464SplayConstIterator<V>::init(SplayNode<V> *head)
465{
466 addLeftPath(head);
467}
468
469template <class V>
470V const &
471SplayConstIterator<V>::operator * () const
472{
473 /* can't dereference when past the end */
474
475 if (toVisit.size() == 0)
476 fatal ("Attempt to dereference SplayConstIterator past-the-end\n");
477
478 return toVisit.top()->data;
479}
480
b5638623 481#endif /* SQUID_SPLAY_H */
f53969cc 482