Initial revision
[profile/ivi/libdrm.git] / libdrm / xf86drmSL.c
1 /* xf86drmSL.c -- Skip list support
2  * Created: Mon May 10 09:28:13 1999 by faith@precisioninsight.com
3  * Revised: Thu Jun  3 16:13:01 1999 by faith@precisioninsight.com
4  *
5  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  * 
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  * 
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26  * 
27  * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmSL.c,v 1.2 1999/06/07 13:01:42 faith Exp $
28  * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/xf86drmSL.c,v 1.1 1999/06/14 07:32:02 dawes Exp $
29  *
30  * DESCRIPTION
31  *
32  * This file contains a straightforward skip list implementation.n
33  *
34  * FUTURE ENHANCEMENTS
35  *
36  * REFERENCES
37  *
38  * [Pugh90] William Pugh.  Skip Lists: A Probabilistic Alternative to
39  * Balanced Trees. CACM 33(6), June 1990, pp. 668-676.
40  *
41  */
42
43 #define SL_MAIN 0
44
45 #if SL_MAIN
46 # include <stdio.h>
47 # include <stdlib.h>
48 #  include <sys/time.h>
49 #else
50 # include "xf86drm.h"
51 # ifdef XFree86LOADER
52 #  include "xf86.h"
53 #  include "xf86_ansic.h"
54 # else
55 #  include <stdio.h>
56 #  include <stdlib.h>
57 # endif
58 #endif
59
60 #define N(x)  drm##x
61
62 #define SL_LIST_MAGIC  0xfacade00LU
63 #define SL_ENTRY_MAGIC 0x00fab1edLU
64 #define SL_FREED_MAGIC 0xdecea5edLU
65 #define SL_MAX_LEVEL   16
66 #define SL_DEBUG       0
67 #define SL_RANDOM_SEED 0xc01055a1LU
68
69 #if SL_MAIN
70 #define SL_ALLOC malloc
71 #define SL_FREE  free
72 #define SL_RANDOM_DECL        static int state = 0;
73 #define SL_RANDOM_INIT(seed)  if (!state) { srandom(seed); ++state; }
74 #define SL_RANDOM             random()
75 #else
76 #define SL_ALLOC drmMalloc
77 #define SL_FREE  drmFree
78 #define SL_RANDOM_DECL        static void *state = NULL
79 #define SL_RANDOM_INIT(seed)  if (!state) state = drmRandomCreate(seed)
80 #define SL_RANDOM             drmRandom(state)
81
82 #endif
83
84 typedef struct SLEntry {
85     unsigned long     magic;       /* SL_ENTRY_MAGIC */
86     unsigned long     key;
87     void              *value;
88     int               levels;
89     struct SLEntry    *forward[1]; /* variable sized array */
90 } SLEntry, *SLEntryPtr;
91
92 typedef struct SkipList {
93     unsigned long    magic;     /* SL_LIST_MAGIC */
94     int              level;
95     int              count;
96     SLEntryPtr       head;
97     SLEntryPtr       p0;        /* Position for iteration */
98 } SkipList, *SkipListPtr;
99
100 #if SL_MAIN
101 extern void *N(SLCreate)(void);
102 extern int  N(SLDestroy)(void *l);
103 extern int  N(SLLookup)(void *l, unsigned long key, void **value);
104 extern int  N(SLInsert)(void *l, unsigned long key, void *value);
105 extern int  N(SLDelete)(void *l, unsigned long key);
106 extern int  N(SLNext)(void *l, unsigned long *key, void **value);
107 extern int  N(SLFirst)(void *l, unsigned long *key, void **value);
108 extern void N(SLDump)(void *l);
109 extern int  N(SLLookupNeighbors)(void *l, unsigned long key,
110                                  unsigned long *prev_key, void **prev_value,
111                                  unsigned long *next_key, void **next_value);
112 #endif
113
114 static SLEntryPtr SLCreateEntry(int max_level, unsigned long key, void *value)
115 {
116     SLEntryPtr entry;
117     
118     if (max_level < 0 || max_level > SL_MAX_LEVEL) max_level = SL_MAX_LEVEL;
119
120     entry         = SL_ALLOC(sizeof(*entry)
121                              + (max_level + 1) * sizeof(entry->forward[0]));
122     if (!entry) return NULL;
123     entry->magic  = SL_ENTRY_MAGIC;
124     entry->key    = key;
125     entry->value  = value;
126     entry->levels = max_level + 1;
127
128     return entry;
129 }
130
131 static int SLRandomLevel(void)
132 {
133     int level = 1;
134     SL_RANDOM_DECL;
135
136     SL_RANDOM_INIT(SL_RANDOM_SEED);
137     
138     while ((SL_RANDOM & 0x01) && level < SL_MAX_LEVEL) ++level;
139     return level;
140 }
141
142 void *N(SLCreate)(void)
143 {
144     SkipListPtr  list;
145     int          i;
146
147     list           = SL_ALLOC(sizeof(*list));
148     if (!list) return NULL;
149     list->magic    = SL_LIST_MAGIC;
150     list->level    = 0;
151     list->head     = SLCreateEntry(SL_MAX_LEVEL, 0, NULL);
152     list->count    = 0;
153
154     for (i = 0; i <= SL_MAX_LEVEL; i++) list->head->forward[i] = NULL;
155     
156     return list;
157 }
158
159 int N(SLDestroy)(void *l)
160 {
161     SkipListPtr   list  = (SkipListPtr)l;
162     SLEntryPtr    entry;
163     SLEntryPtr    next;
164
165     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
166
167     for (entry = list->head; entry; entry = next) {
168         if (entry->magic != SL_ENTRY_MAGIC) return -1; /* Bad magic */
169         next         = entry->forward[0];
170         entry->magic = SL_FREED_MAGIC;
171         SL_FREE(entry);
172     }
173
174     list->magic = SL_FREED_MAGIC;
175     SL_FREE(list);
176     return 0;
177 }
178
179 static SLEntryPtr SLLocate(void *l, unsigned long key, SLEntryPtr *update)
180 {
181     SkipListPtr   list  = (SkipListPtr)l;
182     SLEntryPtr    entry;
183     int           i;
184
185     if (list->magic != SL_LIST_MAGIC) return NULL;
186
187     for (i = list->level, entry = list->head; i >= 0; i--) {
188         while (entry->forward[i] && entry->forward[i]->key < key)
189             entry = entry->forward[i];
190         update[i] = entry;
191     }
192
193     return entry->forward[0];
194 }
195
196 int N(SLInsert)(void *l, unsigned long key, void *value)
197 {
198     SkipListPtr   list  = (SkipListPtr)l;
199     SLEntryPtr    entry;
200     SLEntryPtr    update[SL_MAX_LEVEL + 1];
201     int           level;
202     int           i;
203
204     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
205
206     entry = SLLocate(list, key, update);
207
208     if (entry && entry->key == key) return 1; /* Already in list */
209
210
211     level = SLRandomLevel();
212     if (level > list->level) {
213         level = ++list->level;
214         update[level] = list->head;
215     }
216
217     entry = SLCreateEntry(level, key, value);
218
219                                 /* Fix up forward pointers */
220     for (i = 0; i <= level; i++) {
221         entry->forward[i]     = update[i]->forward[i];
222         update[i]->forward[i] = entry;
223     }
224
225     ++list->count;
226     return 0;                   /* Added to table */
227 }
228
229 int N(SLDelete)(void *l, unsigned long key)
230 {
231     SkipListPtr   list = (SkipListPtr)l;
232     SLEntryPtr    update[SL_MAX_LEVEL + 1];
233     SLEntryPtr    entry;
234     int           i;
235
236     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
237
238     entry = SLLocate(list, key, update);
239
240     if (!entry || entry->key != key) return 1; /* Not found */
241
242                                 /* Fix up forward pointers */
243     for (i = 0; i <= list->level; i++) {
244         if (update[i]->forward[i] == entry)
245             update[i]->forward[i] = entry->forward[i];
246     }
247
248     entry->magic = SL_FREED_MAGIC;
249     SL_FREE(entry);
250
251     while (list->level && !list->head->forward[list->level]) --list->level;
252     --list->count;
253     return 0;
254 }
255
256 int N(SLLookup)(void *l, unsigned long key, void **value)
257 {
258     SkipListPtr   list = (SkipListPtr)l;
259     SLEntryPtr    update[SL_MAX_LEVEL + 1];
260     SLEntryPtr    entry;
261
262     entry = SLLocate(list, key, update);
263
264     if (entry && entry->key == key) {
265         *value = entry;
266         return 0;
267     }
268     *value = NULL;
269     return -1;
270 }
271
272 int N(SLLookupNeighbors)(void *l, unsigned long key,
273                          unsigned long *prev_key, void **prev_value,
274                          unsigned long *next_key, void **next_value)
275 {
276     SkipListPtr   list = (SkipListPtr)l;
277     SLEntryPtr    update[SL_MAX_LEVEL + 1];
278     SLEntryPtr    entry;
279     int           retcode = 0;
280
281     entry = SLLocate(list, key, update);
282
283     *prev_key   = *next_key   = key;
284     *prev_value = *next_value = NULL;
285         
286     if (update[0]) {
287         *prev_key   = update[0]->key;
288         *prev_value = update[0]->value;
289         ++retcode;
290         if (update[0]->forward[0]) {
291             *next_key   = update[0]->forward[0]->key;
292             *next_value = update[0]->forward[0]->value;
293             ++retcode;
294         }
295     }
296     return retcode;
297 }
298
299 int N(SLNext)(void *l, unsigned long *key, void **value)
300 {
301     SkipListPtr   list = (SkipListPtr)l;
302     SLEntryPtr    entry;
303     
304     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
305
306     entry    = list->p0;
307
308     if (entry) {
309         list->p0 = entry->forward[0];
310         *key     = entry->key;
311         *value   = entry->value;
312         return 1;
313     }
314     list->p0 = NULL;
315     return 0;
316 }
317
318 int N(SLFirst)(void *l, unsigned long *key, void **value)
319 {
320     SkipListPtr   list = (SkipListPtr)l;
321     
322     if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
323     
324     list->p0 = list->head->forward[0];
325     return N(SLNext)(list, key, value);
326 }
327
328 /* Dump internal data structures for debugging. */
329 void N(SLDump)(void *l)
330 {
331     SkipListPtr   list = (SkipListPtr)l;
332     SLEntryPtr    entry;
333     int           i;
334     
335     if (list->magic != SL_LIST_MAGIC) {
336         printf("Bad magic: 0x%08lx (expected 0x%08lx)\n",
337                list->magic, SL_LIST_MAGIC);
338         return;
339     }
340
341     printf("Level = %d, count = %d\n", list->level, list->count);
342     for (entry = list->head; entry; entry = entry->forward[0]) {
343         if (entry->magic != SL_ENTRY_MAGIC) {
344             printf("Bad magic: 0x%08lx (expected 0x%08lx)\n",
345                    list->magic, SL_ENTRY_MAGIC);
346         }
347         printf("\nEntry %p <0x%08lx, %p> has %2d levels\n",
348                entry, entry->key, entry->value, entry->levels);
349         for (i = 0; i < entry->levels; i++) {
350             if (entry->forward[i]) {
351                 printf("   %2d: %p <0x%08lx, %p>\n",
352                        i,
353                        entry->forward[i],
354                        entry->forward[i]->key,
355                        entry->forward[i]->value);
356             } else {
357                 printf("   %2d: %p\n", i, entry->forward[i]);
358             }
359         }
360     }
361 }
362
363 #if SL_MAIN
364 static void print(SkipListPtr list)
365 {
366     unsigned long key;
367     void          *value;
368     
369     if (N(SLFirst)(list, &key, &value)) {
370         do {
371             printf("key = %5lu, value = %p\n", key, value);
372         } while (N(SLNext)(list, &key, &value));
373     }
374 }
375
376 static double do_time(int size, int iter)
377 {
378     SkipListPtr    list;
379     int            i, j;
380     unsigned long  keys[1000000];
381     unsigned long  previous;
382     unsigned long  key;
383     void           *value;
384     struct timeval start, stop;
385     double         usec;
386     SL_RANDOM_DECL;
387
388     SL_RANDOM_INIT(12345);
389     
390     list = N(SLCreate)();
391
392     for (i = 0; i < size; i++) {
393         keys[i] = SL_RANDOM;
394         N(SLInsert)(list, keys[i], NULL);
395     }
396
397     previous = 0;
398     if (N(SLFirst)(list, &key, &value)) {
399         do {
400             if (key <= previous) {
401                 printf( "%lu !< %lu\n", previous, key);
402             }
403             previous = key;
404         } while (N(SLNext)(list, &key, &value));
405     }
406     
407     gettimeofday(&start, NULL);
408     for (j = 0; j < iter; j++) {
409         for (i = 0; i < size; i++) {
410             if (N(SLLookup)(list, keys[i], &value))
411                 printf("Error %lu %d\n", keys[i], i);
412         }
413     }
414     gettimeofday(&stop, NULL);
415     
416     usec = (double)(stop.tv_sec * 1000000 + stop.tv_usec
417                     - start.tv_sec * 1000000 - start.tv_usec) / (size * iter);
418     
419     printf("%0.2f microseconds for list length %d\n", usec, size);
420
421     N(SLDestroy)(list);
422     
423     return usec;
424 }
425
426 static void print_neighbors(void *list, unsigned long key)
427 {
428     unsigned long prev_key = 0;
429     unsigned long next_key = 0;
430     void          *prev_value;
431     void          *next_value;
432     int           retval;
433
434     retval = drmSLLookupNeighbors(list, key,
435                                   &prev_key, &prev_value,
436                                   &next_key, &next_value);
437     printf("Neighbors of %5lu: %d %5lu %5lu\n",
438            key, retval, prev_key, next_key);
439 }
440
441 int main(void)
442 {
443     SkipListPtr    list;
444     double         usec, usec2, usec3, usec4;
445
446     list = N(SLCreate)();
447     printf( "list at %p\n", list);
448
449     print(list);
450     printf("\n==============================\n\n");
451
452     N(SLInsert)(list, 123, NULL);
453     N(SLInsert)(list, 213, NULL);
454     N(SLInsert)(list, 50, NULL);
455     print(list);
456     printf("\n==============================\n\n");
457     
458     print_neighbors(list, 0);
459     print_neighbors(list, 50);
460     print_neighbors(list, 51);
461     print_neighbors(list, 123);
462     print_neighbors(list, 200);
463     print_neighbors(list, 213);
464     print_neighbors(list, 256);
465     printf("\n==============================\n\n");    
466     
467     N(SLDelete)(list, 50);
468     print(list);
469     printf("\n==============================\n\n");
470
471     N(SLDump)(list);
472     N(SLDestroy)(list);
473     printf("\n==============================\n\n");
474
475     usec  = do_time(100, 10000);
476     usec2 = do_time(1000, 500);
477     printf("Table size increased by %0.2f, search time increased by %0.2f\n",
478            1000.0/100.0, usec2 / usec);
479     
480     usec3 = do_time(10000, 50);
481     printf("Table size increased by %0.2f, search time increased by %0.2f\n",
482            10000.0/100.0, usec3 / usec);
483     
484     usec4 = do_time(100000, 4);
485     printf("Table size increased by %0.2f, search time increased by %0.2f\n",
486            100000.0/100.0, usec4 / usec);
487
488     return 0;
489 }
490 #endif