Lumiera  0.pre.03
»edit your freedom«
psplay.c
Go to the documentation of this file.
1 /*
2  psplay.c - probabilistic splay tree
3 
4  Copyright (C) (contributed to CinelerraCV)
5  2004-2006, Christian Thaeter <chth@gmx.net>
6  Copyright (C)
7  2007, 2008, Christian Thaeter <ct@pipapo.org>
8 
9   **Lumiera** is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2 of the License, or (at your
12   option) any later version. See the file COPYING for further details.
13 */
14 
15 
20 #include "include/logging.h"
21 #include "lib/psplay.h"
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <nobug.h>
27 
28 //NOBUG_DEFINE_FLAG (psplay);
29 
30 #ifndef PSPLAY_TRAIL_DEPTH
31 #define PSPLAY_TRAIL_DEPTH 128
32 #endif
33 
34 /*
35  probabilistic distribution, this are the direct splay equations used to determine if to splay
36  or break out of the splaying algorithm.
37 
38  useable variables/functions are:
39  self->log2 - log2 of the tree elements, this would be the depth of a fully balanced tree
40  splayfactor - user defined weigth for splaying, we define '100' to be the default
41  depth - depth of the current node in the tree
42  trail->dir - dervitation from tree center
43  psplay_fast_prng () - returns a prng in the range 1...2^31
44 */
45 
46 #define PSPLAY_FORMULA (self->log2*100/(depth + (psplay_fast_prng () & 63)) + trail->dir) * splayfactor
47 
48 #ifndef PSPLAY_PROB_ZIGZIG
49 #define PSPLAY_PROB_ZIGZIG 5000
50 #endif
51 #ifndef PSPLAY_PROB_ZIGZAG
52 #define PSPLAY_PROB_ZIGZAG 2500
53 #endif
54 
55 
56 
57 /* simple prng with 2^31-1 cycle */
58 static inline uint32_t psplay_fast_prng ()
59 {
60  static uint32_t rnd=0xbabeface;
61  return rnd = rnd<<1 ^ ((rnd >> 30) & 1) ^ ((rnd>>2) & 1);
62 }
63 
64 
65 PSplay
67 {
68  //NOBUG_INIT_FLAG (psplay);
69  TRACE (psplay_dbg);
70  REQUIRE (cmp);
71  REQUIRE (key);
72 
73  if (self)
74  {
75  self->tree = NULL;
76  self->found_parent = &self->tree;
77  self->cmp = cmp;
78  self->key = key;
79  self->del = del;
80  self->elem_cnt = 0;
81  self->log2 = 0;
82  }
83  return self;
84 }
85 
86 
87 PSplay
89 {
90  PSplay self = malloc (sizeof *self);
91  if (self)
92  {
93  psplay_init (self , cmp, key, del);
94  }
95  return self;
96 }
97 
98 
99 
100 PSplay
101 psplay_destroy (PSplay self)
102 {
103  TRACE (psplay_dbg);
104  if (self) while (self->tree)
105  {
106  PSplaynode n = psplay_remove (self, self->tree);
107  if (self->del)
108  self->del (n);
109  }
110  return self;
111 }
112 
113 
114 void
115 psplay_delete (PSplay self)
116 {
117  free (psplay_destroy (self));
118 }
119 
120 
121 PSplaynode
122 psplaynode_init (PSplaynode self)
123 {
124  if (self)
125  self->left = self->right = NULL;
126  return self;
127 }
128 
129 
130 
131 /*
132  Lookup operations (lookup and insert) record the path as they decend into the tree
133  this will allow bottom up splaying without storing 'up' pointers in the node.
134  The length of this trail (PSPLAY_TRAIL_DEPTH) also define the maximal limit on how much
135  a node can be splayed up giving some hard bound for the splay operation.
136 
137  General wisdom tells that top down splaying is more efficent to implement than bottom
138  up splaying. Nevertheless we do bottom up splaying here because we can decide
139  randomly on each level if we want to continue splaying or not. No splaying
140  is certainly more efficent than top-down splaying.
141 */
143 {
144  int dir;
145  unsigned depth;
146  PSplaynode* trail[PSPLAY_TRAIL_DEPTH];
147 };
148 
149 static inline unsigned
150 trailidx (unsigned n)
151 {
152  return n & (PSPLAY_TRAIL_DEPTH-1);
153 }
154 
155 
156 static inline void
157 psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor)
158 {
159  TRACE (psplay_dbg, "%p %u", self, splayfactor);
160 
161  if (trail->dir < 0) trail->dir = - trail->dir;
162 
163  for (unsigned lim = PSPLAY_TRAIL_DEPTH, depth = trail->depth; lim > 2 && depth > 2; lim-=2, depth-=2)
164  {
165  PSplaynode node = *trail->trail [trailidx (depth)];
166  PSplaynode parent = *trail->trail [trailidx (depth-1)];
167  PSplaynode grandparent = *trail->trail [trailidx (depth-2)];
168 
169  unsigned r = PSPLAY_FORMULA;
170  TRACE (psplay_dbg, "r is %u", r);
171 
172  if (parent == grandparent->left)
173  {
174  TRACE (psplay_dbg, "ZIG..");
175  if (node == parent->left)
176  {
177  TRACE (psplay_dbg, "..ZIG");
178  if (r < PSPLAY_PROB_ZIGZIG)
179  {
180  TRACE (psplay_dbg, "BREAK");
181  return;
182  }
183 
184  grandparent->left = parent->right;
185  parent->right = grandparent;
186 
187  parent->left = node->right;
188  node->right = parent;
189  }
190  else
191  {
192  TRACE (psplay_dbg, "..ZAG");
193  if (r < PSPLAY_PROB_ZIGZAG)
194  {
195  TRACE (psplay_dbg, "BREAK");
196  return;
197  }
198 
199  parent->right = node->left;
200  node->left = parent;
201 
202  grandparent->left = node->right;
203  node->right = grandparent;
204  }
205  }
206  else
207  {
208  TRACE (psplay_dbg, "ZAG..");
209  if (node == parent->left)
210  {
211  TRACE (psplay_dbg, "..ZIG");
212  if (r < PSPLAY_PROB_ZIGZAG)
213  {
214  TRACE (psplay_dbg, "BREAK");
215  return;
216  }
217 
218  parent->left = node->right;
219  node->right = parent;
220 
221  grandparent->right = node->left;
222  node->left = grandparent;
223  }
224  else
225  {
226  TRACE (psplay_dbg, "..ZAG");
227  if (r < PSPLAY_PROB_ZIGZIG)
228  {
229  TRACE (psplay_dbg, "BREAK");
230  return;
231  }
232 
233  grandparent->right = parent->left;
234  parent->left = grandparent;
235 
236  parent->right = node->left;
237  node->left = parent;
238  }
239  }
240  *trail->trail [trailidx (depth-2)] = node;
241  }
242 }
243 
244 
245 PSplaynode
246 psplay_insert (PSplay self, PSplaynode node, int splayfactor)
247 {
248  TRACE (psplay_dbg);
249  PSplaynode n = self->tree;
250  struct psplaytrail trail;
251 
252  trail.dir = 0;
253  trail.depth = 0;
254  trail.trail [0] = &self->tree;
255 
256  if (!n)
257  self->tree = node;
258  else
259  {
260  while (n != node)
261  {
262  int c;
263  c = self->cmp (self->key (node), self->key (n));
264  ++trail.depth;
265 
266  if (c < 0)
267  {
268  --trail.dir;
269  if (!n->left)
270  n->left = node;
271  trail.trail [trailidx (trail.depth)] = &n->left;
272  n = n->left;
273  }
274  else if (c > 0)
275  {
276  ++trail.dir;
277  if (!n->right)
278  n->right = node;
279  trail.trail [trailidx (trail.depth)] = &n->right;
280  n = n->right;
281  }
282  else
283  {
284  WARN (psplay_dbg, "dropping duplicate entry for psplay");
286  return NULL;
287  }
288  }
289  }
290  ++self->elem_cnt;
291  if (self->elem_cnt >= 1UL<<self->log2) ++self->log2;
292  if (splayfactor && trail.depth > 2)
293  psplay_splay (self, &trail, splayfactor);
294  return node;
295 }
296 
297 
298 
299 PSplaynode
300 psplay_find (PSplay self, const void* key, int splayfactor)
301 {
302  TRACE (psplay_dbg);
303  PSplaynode node = self->tree;
304  struct psplaytrail trail;
305  trail.dir = 0;
306  trail.depth = 0;
307  trail.trail [0] = &self->tree;
308 
309  while (node)
310  {
311  int c;
312  c = self->cmp (key, self->key (node));
313  ++trail.depth;
314 
315  if (c < 0)
316  {
317  --trail.dir;
318  trail.trail [trailidx (trail.depth)] = &node->left;
319  node = node->left;
320  }
321  else if (c > 0)
322  {
323  ++trail.dir;
324  trail.trail [trailidx (trail.depth)] = &node->right;
325  node = node->right;
326  }
327  else
328  {
329  self->found_parent = trail.trail [trailidx (--trail.depth)];
330  break;
331  }
332  }
333  if (node && splayfactor && trail.depth > 2)
334  psplay_splay (self, &trail, splayfactor);
335  return node;
336 }
337 
338 
339 PSplaynode
340 psplay_remove (PSplay self, PSplaynode node)
341 {
342  TRACE (psplay_dbg);
343  if (!node) return NULL;
344 
345  PSplaynode* r = self->found_parent;
346 
347  while (*r != node)
348  {
349  if (!psplay_find (self, self->key (node), 0))
350  {
351  WARN (psplay_dbg, "node %p is not in splay tree %p", node, self);
352  return NULL;
353  }
354  r = self->found_parent;
355  }
356 
357  if (!node->left)
358  *r = node->right;
359  else if (!node->right)
360  *r = node->left;
361  else
362  {
363  PSplaynode i, iparent = NULL;
364  if (psplay_fast_prng()&1) /* 50% probability removing left or right wards */
365  {
366  for (i = node->left; i->right; iparent = i, i = i->right);
367  if (iparent)
368  iparent->right = i->left;
369  if (node->left != i)
370  i->left = node->left;
371  i->right = node->right;
372  }
373  else
374  {
375  for (i = node->right; i->left; iparent = i, i = i->left);
376  if (iparent)
377  iparent->left = i->right;
378  if (node->right != i)
379  i->right = node->right;
380  i->left = node->left;
381  }
382  *r = i;
383  }
384  --self->elem_cnt;
385  if (self->elem_cnt < 1UL<<self->log2) --self->log2;
386  return node;
387 }
388 
389 
390 PSplaynode
391 psplay_remove_key (PSplay self, void* key)
392 {
393  return psplay_remove (self, psplay_find (self, key, 0));
394 }
395 
396 
397 void
398 psplay_delete_node (PSplay self, PSplaynode node)
399 {
400  if (node)
401  self->del (psplay_remove (self, node));
402 }
403 
404 
405 void
406 psplay_delete_key (PSplay self, void* key)
407 {
408  PSplaynode node = psplay_find (self, key, 0);
409  psplay_delete_node (self, node);
410 }
411 
412 
413 
414 const psplay_delete_fn PSPLAY_CONT = (psplay_delete_fn)0x0;
415 const psplay_delete_fn PSPLAY_STOP = (psplay_delete_fn)0x1;
416 const psplay_delete_fn PSPLAY_REMOVE = (psplay_delete_fn)0x2;
417 
418 static int
419 psplay_handle (PSplay self, PSplaynode node, psplay_delete_fn res)
420 {
421  if (res == PSPLAY_CONT)
422  return 1;
423 
424  if (res == PSPLAY_STOP)
425  ;
426  else if (res == PSPLAY_REMOVE)
427  {
428  psplay_remove (self, node);
429  if (self->del)
430  self->del (node);
431  }
432  else
433  {
434  psplay_remove (self, node);
435  res (node);
436  }
437  return 0;
438 }
439 
440 
441 int
442 psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data)
443 {
444  if (!self->tree)
445  return 1;
446 
447  if (!node)
448  node = self->tree;
449 
450  psplay_delete_fn res;
451 
452  res = action (node, PSPLAY_PREORDER, level, data);
453  if (!psplay_handle (self, node, res))
454  return 0;
455 
456  if (node->left)
457  if (!psplay_walk (self, node->left, action, level+1, data))
458  return 0;
459 
460  res = action (node, PSPLAY_INORDER, level, data);
461  if (!psplay_handle (self, node, res))
462  return 0;
463 
464  if (node->right)
465  if (!psplay_walk (self, node->right, action, level+1, data))
466  return 0;
467 
468  res = action (node, PSPLAY_POSTORDER, level, data);
469  if (!psplay_handle (self, node, res))
470  return 0;
471 
472  return 1;
473 }
474 
475 
476 static psplay_delete_fn
477 psplay_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
478 {
479  FILE* fh = data;
480  static char* sp = " ";
481  if (level>40)
482  {
483  if (which == PSPLAY_PREORDER)
484  fprintf (fh, "%s ...\n", sp);
485  return PSPLAY_CONT;
486  }
487 
488  switch (which)
489  {
490  case PSPLAY_PREORDER:
491  fprintf (fh, "%s%p\n", sp+40-level, node);
492  if (node->left)
493  fprintf (fh, "%sleft %p\n", sp+40-level, node->left);
494  break;
495  case PSPLAY_INORDER:
496  if (node->right)
497  fprintf (fh, "%sright %p\n", sp+40-level, node->right);
498  break;
499  case PSPLAY_POSTORDER:
500  break;
501  }
502 
503  return PSPLAY_CONT;
504 }
505 
506 void
507 psplay_dump (PSplay self, FILE* dest)
508 {
509  fprintf (dest, "root %p\n", self->tree);
510  psplay_walk (self, NULL, psplay_print_node, 0, dest);
511 }
512 
513 
514 /*
515 // Local Variables:
516 // mode: C
517 // c-file-style: "gnu"
518 // indent-tabs-mode: nil
519 // End:
520 */
PSplay psplay_destroy(PSplay self)
Destroy a splay tree Frees all elements and associated resources of a splay tree. ...
Definition: psplay.c:101
psplay_delete_fn(* psplay_action_fn)(PSplaynode node, const enum psplay_order_enum which, int level, void *data)
Traverse a splay tree Traversing a tree calls a user supplied action three times An &#39;action&#39; must not...
Definition: psplay.h:256
PSplay psplay_init(PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del)
Initialize a splay tree.
Definition: psplay.c:66
const void *(* psplay_key_fn)(const PSplaynode node)
Retrieve the key from a user datastructure.
Definition: psplay.h:73
This header is for including and configuring NoBug.
PSplaynode psplay_find(PSplay self, const void *key, int splayfactor)
Find a element in a splay tree.
Definition: psplay.c:300
PSplaynode psplay_insert(PSplay self, PSplaynode node, int splayfactor)
Insert a element into a splay tree.
Definition: psplay.c:246
void psplay_delete(PSplay self)
Delete a splay tree Frees all elements and associated resources of a splay tree and then itseld...
Definition: psplay.c:115
PSplay psplay_new(psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn del)
Allocate a splay tree.
Definition: psplay.c:88
Probabilistic splay tree.
int(* psplay_cmp_fn)(const void *a, const void *b)
Function use to compare keys.
Definition: psplay.h:55
PSplaynode psplay_remove(PSplay self, PSplaynode node)
Remove a node from a splay tree.
Definition: psplay.c:340
int psplay_walk(PSplay self, PSplaynode node, psplay_action_fn action, int level, void *data)
Start a tree traversal.
Definition: psplay.c:442
PSplaynode psplay_remove_key(PSplay self, void *key)
Remove a node by key from a splay tree.
Definition: psplay.c:391
void psplay_delete_key(PSplay self, void *key)
Delete a node by key from a splay tree.
Definition: psplay.c:406
PSplaynode psplaynode_init(PSplaynode self)
Initialise a splay tree node The user has to place this nodes within his datastructure and must Initi...
Definition: psplay.c:122
void(* psplay_delete_fn)(PSplaynode node)
Destructor for user defined data Called when an element got removed from a splay tree.
Definition: psplay.h:65
void psplay_delete_node(PSplay self, PSplaynode node)
Delete a node from a splay tree.
Definition: psplay.c:398