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