xf86drmSL.c revision 22944501
122944501Smrg/* xf86drmSL.c -- Skip list support
222944501Smrg * Created: Mon May 10 09:28:13 1999 by faith@precisioninsight.com
322944501Smrg *
422944501Smrg * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
522944501Smrg * All Rights Reserved.
622944501Smrg *
722944501Smrg * Permission is hereby granted, free of charge, to any person obtaining a
822944501Smrg * copy of this software and associated documentation files (the "Software"),
922944501Smrg * to deal in the Software without restriction, including without limitation
1022944501Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1122944501Smrg * and/or sell copies of the Software, and to permit persons to whom the
1222944501Smrg * Software is furnished to do so, subject to the following conditions:
1322944501Smrg *
1422944501Smrg * The above copyright notice and this permission notice (including the next
1522944501Smrg * paragraph) shall be included in all copies or substantial portions of the
1622944501Smrg * Software.
1722944501Smrg *
1822944501Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1922944501Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2022944501Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2122944501Smrg * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2222944501Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2322944501Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2422944501Smrg * DEALINGS IN THE SOFTWARE.
2522944501Smrg *
2622944501Smrg * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
2722944501Smrg *
2822944501Smrg * DESCRIPTION
2922944501Smrg *
3022944501Smrg * This file contains a straightforward skip list implementation.n
3122944501Smrg *
3222944501Smrg * FUTURE ENHANCEMENTS
3322944501Smrg *
3422944501Smrg * REFERENCES
3522944501Smrg *
3622944501Smrg * [Pugh90] William Pugh.  Skip Lists: A Probabilistic Alternative to
3722944501Smrg * Balanced Trees. CACM 33(6), June 1990, pp. 668-676.
3822944501Smrg *
3922944501Smrg */
4022944501Smrg
4122944501Smrg#include <stdio.h>
4222944501Smrg#include <stdlib.h>
4322944501Smrg
4422944501Smrg#define SL_MAIN 0
4522944501Smrg
4622944501Smrg#if !SL_MAIN
4722944501Smrg# include "xf86drm.h"
4822944501Smrg#else
4922944501Smrg# include <sys/time.h>
5022944501Smrg#endif
5122944501Smrg
5222944501Smrg#define SL_LIST_MAGIC  0xfacade00LU
5322944501Smrg#define SL_ENTRY_MAGIC 0x00fab1edLU
5422944501Smrg#define SL_FREED_MAGIC 0xdecea5edLU
5522944501Smrg#define SL_MAX_LEVEL   16
5622944501Smrg#define SL_DEBUG       0
5722944501Smrg#define SL_RANDOM_SEED 0xc01055a1LU
5822944501Smrg
5922944501Smrg#if SL_MAIN
6022944501Smrg#define SL_ALLOC malloc
6122944501Smrg#define SL_FREE  free
6222944501Smrg#define SL_RANDOM_DECL        static int state = 0;
6322944501Smrg#define SL_RANDOM_INIT(seed)  if (!state) { srandom(seed); ++state; }
6422944501Smrg#define SL_RANDOM             random()
6522944501Smrg#else
6622944501Smrg#define SL_ALLOC drmMalloc
6722944501Smrg#define SL_FREE  drmFree
6822944501Smrg#define SL_RANDOM_DECL        static void *state = NULL
6922944501Smrg#define SL_RANDOM_INIT(seed)  if (!state) state = drmRandomCreate(seed)
7022944501Smrg#define SL_RANDOM             drmRandom(state)
7122944501Smrg
7222944501Smrg#endif
7322944501Smrg
7422944501Smrgtypedef struct SLEntry {
7522944501Smrg    unsigned long     magic;	   /* SL_ENTRY_MAGIC */
7622944501Smrg    unsigned long     key;
7722944501Smrg    void              *value;
7822944501Smrg    int               levels;
7922944501Smrg    struct SLEntry    *forward[1]; /* variable sized array */
8022944501Smrg} SLEntry, *SLEntryPtr;
8122944501Smrg
8222944501Smrgtypedef struct SkipList {
8322944501Smrg    unsigned long    magic;	/* SL_LIST_MAGIC */
8422944501Smrg    int              level;
8522944501Smrg    int              count;
8622944501Smrg    SLEntryPtr       head;
8722944501Smrg    SLEntryPtr       p0;	/* Position for iteration */
8822944501Smrg} SkipList, *SkipListPtr;
8922944501Smrg
9022944501Smrg#if SL_MAIN
9122944501Smrgextern void *drmSLCreate(void);
9222944501Smrgextern int  drmSLDestroy(void *l);
9322944501Smrgextern int  drmSLLookup(void *l, unsigned long key, void **value);
9422944501Smrgextern int  drmSLInsert(void *l, unsigned long key, void *value);
9522944501Smrgextern int  drmSLDelete(void *l, unsigned long key);
9622944501Smrgextern int  drmSLNext(void *l, unsigned long *key, void **value);
9722944501Smrgextern int  drmSLFirst(void *l, unsigned long *key, void **value);
9822944501Smrgextern void drmSLDump(void *l);
9922944501Smrgextern int  drmSLLookupNeighbors(void *l, unsigned long key,
10022944501Smrg				 unsigned long *prev_key, void **prev_value,
10122944501Smrg				 unsigned long *next_key, void **next_value);
10222944501Smrg#endif
10322944501Smrg
10422944501Smrgstatic SLEntryPtr SLCreateEntry(int max_level, unsigned long key, void *value)
10522944501Smrg{
10622944501Smrg    SLEntryPtr entry;
10722944501Smrg
10822944501Smrg    if (max_level < 0 || max_level > SL_MAX_LEVEL) max_level = SL_MAX_LEVEL;
10922944501Smrg
11022944501Smrg    entry         = SL_ALLOC(sizeof(*entry)
11122944501Smrg			     + (max_level + 1) * sizeof(entry->forward[0]));
11222944501Smrg    if (!entry) return NULL;
11322944501Smrg    entry->magic  = SL_ENTRY_MAGIC;
11422944501Smrg    entry->key    = key;
11522944501Smrg    entry->value  = value;
11622944501Smrg    entry->levels = max_level + 1;
11722944501Smrg
11822944501Smrg    return entry;
11922944501Smrg}
12022944501Smrg
12122944501Smrgstatic int SLRandomLevel(void)
12222944501Smrg{
12322944501Smrg    int level = 1;
12422944501Smrg    SL_RANDOM_DECL;
12522944501Smrg
12622944501Smrg    SL_RANDOM_INIT(SL_RANDOM_SEED);
12722944501Smrg
12822944501Smrg    while ((SL_RANDOM & 0x01) && level < SL_MAX_LEVEL) ++level;
12922944501Smrg    return level;
13022944501Smrg}
13122944501Smrg
13222944501Smrgvoid *drmSLCreate(void)
13322944501Smrg{
13422944501Smrg    SkipListPtr  list;
13522944501Smrg    int          i;
13622944501Smrg
13722944501Smrg    list           = SL_ALLOC(sizeof(*list));
13822944501Smrg    if (!list) return NULL;
13922944501Smrg    list->magic    = SL_LIST_MAGIC;
14022944501Smrg    list->level    = 0;
14122944501Smrg    list->head     = SLCreateEntry(SL_MAX_LEVEL, 0, NULL);
14222944501Smrg    list->count    = 0;
14322944501Smrg
14422944501Smrg    for (i = 0; i <= SL_MAX_LEVEL; i++) list->head->forward[i] = NULL;
14522944501Smrg
14622944501Smrg    return list;
14722944501Smrg}
14822944501Smrg
14922944501Smrgint drmSLDestroy(void *l)
15022944501Smrg{
15122944501Smrg    SkipListPtr   list  = (SkipListPtr)l;
15222944501Smrg    SLEntryPtr    entry;
15322944501Smrg    SLEntryPtr    next;
15422944501Smrg
15522944501Smrg    if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
15622944501Smrg
15722944501Smrg    for (entry = list->head; entry; entry = next) {
15822944501Smrg	if (entry->magic != SL_ENTRY_MAGIC) return -1; /* Bad magic */
15922944501Smrg	next         = entry->forward[0];
16022944501Smrg	entry->magic = SL_FREED_MAGIC;
16122944501Smrg	SL_FREE(entry);
16222944501Smrg    }
16322944501Smrg
16422944501Smrg    list->magic = SL_FREED_MAGIC;
16522944501Smrg    SL_FREE(list);
16622944501Smrg    return 0;
16722944501Smrg}
16822944501Smrg
16922944501Smrgstatic SLEntryPtr SLLocate(void *l, unsigned long key, SLEntryPtr *update)
17022944501Smrg{
17122944501Smrg    SkipListPtr   list  = (SkipListPtr)l;
17222944501Smrg    SLEntryPtr    entry;
17322944501Smrg    int           i;
17422944501Smrg
17522944501Smrg    if (list->magic != SL_LIST_MAGIC) return NULL;
17622944501Smrg
17722944501Smrg    for (i = list->level, entry = list->head; i >= 0; i--) {
17822944501Smrg	while (entry->forward[i] && entry->forward[i]->key < key)
17922944501Smrg	    entry = entry->forward[i];
18022944501Smrg	update[i] = entry;
18122944501Smrg    }
18222944501Smrg
18322944501Smrg    return entry->forward[0];
18422944501Smrg}
18522944501Smrg
18622944501Smrgint drmSLInsert(void *l, unsigned long key, void *value)
18722944501Smrg{
18822944501Smrg    SkipListPtr   list  = (SkipListPtr)l;
18922944501Smrg    SLEntryPtr    entry;
19022944501Smrg    SLEntryPtr    update[SL_MAX_LEVEL + 1];
19122944501Smrg    int           level;
19222944501Smrg    int           i;
19322944501Smrg
19422944501Smrg    if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
19522944501Smrg
19622944501Smrg    entry = SLLocate(list, key, update);
19722944501Smrg
19822944501Smrg    if (entry && entry->key == key) return 1; /* Already in list */
19922944501Smrg
20022944501Smrg
20122944501Smrg    level = SLRandomLevel();
20222944501Smrg    if (level > list->level) {
20322944501Smrg	level = ++list->level;
20422944501Smrg	update[level] = list->head;
20522944501Smrg    }
20622944501Smrg
20722944501Smrg    entry = SLCreateEntry(level, key, value);
20822944501Smrg
20922944501Smrg				/* Fix up forward pointers */
21022944501Smrg    for (i = 0; i <= level; i++) {
21122944501Smrg	entry->forward[i]     = update[i]->forward[i];
21222944501Smrg	update[i]->forward[i] = entry;
21322944501Smrg    }
21422944501Smrg
21522944501Smrg    ++list->count;
21622944501Smrg    return 0;			/* Added to table */
21722944501Smrg}
21822944501Smrg
21922944501Smrgint drmSLDelete(void *l, unsigned long key)
22022944501Smrg{
22122944501Smrg    SkipListPtr   list = (SkipListPtr)l;
22222944501Smrg    SLEntryPtr    update[SL_MAX_LEVEL + 1];
22322944501Smrg    SLEntryPtr    entry;
22422944501Smrg    int           i;
22522944501Smrg
22622944501Smrg    if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
22722944501Smrg
22822944501Smrg    entry = SLLocate(list, key, update);
22922944501Smrg
23022944501Smrg    if (!entry || entry->key != key) return 1; /* Not found */
23122944501Smrg
23222944501Smrg				/* Fix up forward pointers */
23322944501Smrg    for (i = 0; i <= list->level; i++) {
23422944501Smrg	if (update[i]->forward[i] == entry)
23522944501Smrg	    update[i]->forward[i] = entry->forward[i];
23622944501Smrg    }
23722944501Smrg
23822944501Smrg    entry->magic = SL_FREED_MAGIC;
23922944501Smrg    SL_FREE(entry);
24022944501Smrg
24122944501Smrg    while (list->level && !list->head->forward[list->level]) --list->level;
24222944501Smrg    --list->count;
24322944501Smrg    return 0;
24422944501Smrg}
24522944501Smrg
24622944501Smrgint drmSLLookup(void *l, unsigned long key, void **value)
24722944501Smrg{
24822944501Smrg    SkipListPtr   list = (SkipListPtr)l;
24922944501Smrg    SLEntryPtr    update[SL_MAX_LEVEL + 1];
25022944501Smrg    SLEntryPtr    entry;
25122944501Smrg
25222944501Smrg    entry = SLLocate(list, key, update);
25322944501Smrg
25422944501Smrg    if (entry && entry->key == key) {
25522944501Smrg	*value = entry;
25622944501Smrg	return 0;
25722944501Smrg    }
25822944501Smrg    *value = NULL;
25922944501Smrg    return -1;
26022944501Smrg}
26122944501Smrg
26222944501Smrgint drmSLLookupNeighbors(void *l, unsigned long key,
26322944501Smrg			 unsigned long *prev_key, void **prev_value,
26422944501Smrg			 unsigned long *next_key, void **next_value)
26522944501Smrg{
26622944501Smrg    SkipListPtr   list = (SkipListPtr)l;
26722944501Smrg    SLEntryPtr    update[SL_MAX_LEVEL + 1];
26822944501Smrg    int           retcode = 0;
26922944501Smrg
27022944501Smrg    *prev_key   = *next_key   = key;
27122944501Smrg    *prev_value = *next_value = NULL;
27222944501Smrg
27322944501Smrg    if (update[0]) {
27422944501Smrg	*prev_key   = update[0]->key;
27522944501Smrg	*prev_value = update[0]->value;
27622944501Smrg	++retcode;
27722944501Smrg	if (update[0]->forward[0]) {
27822944501Smrg	    *next_key   = update[0]->forward[0]->key;
27922944501Smrg	    *next_value = update[0]->forward[0]->value;
28022944501Smrg	    ++retcode;
28122944501Smrg	}
28222944501Smrg    }
28322944501Smrg    return retcode;
28422944501Smrg}
28522944501Smrg
28622944501Smrgint drmSLNext(void *l, unsigned long *key, void **value)
28722944501Smrg{
28822944501Smrg    SkipListPtr   list = (SkipListPtr)l;
28922944501Smrg    SLEntryPtr    entry;
29022944501Smrg
29122944501Smrg    if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
29222944501Smrg
29322944501Smrg    entry    = list->p0;
29422944501Smrg
29522944501Smrg    if (entry) {
29622944501Smrg	list->p0 = entry->forward[0];
29722944501Smrg	*key     = entry->key;
29822944501Smrg	*value   = entry->value;
29922944501Smrg	return 1;
30022944501Smrg    }
30122944501Smrg    list->p0 = NULL;
30222944501Smrg    return 0;
30322944501Smrg}
30422944501Smrg
30522944501Smrgint drmSLFirst(void *l, unsigned long *key, void **value)
30622944501Smrg{
30722944501Smrg    SkipListPtr   list = (SkipListPtr)l;
30822944501Smrg
30922944501Smrg    if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */
31022944501Smrg
31122944501Smrg    list->p0 = list->head->forward[0];
31222944501Smrg    return drmSLNext(list, key, value);
31322944501Smrg}
31422944501Smrg
31522944501Smrg/* Dump internal data structures for debugging. */
31622944501Smrgvoid drmSLDump(void *l)
31722944501Smrg{
31822944501Smrg    SkipListPtr   list = (SkipListPtr)l;
31922944501Smrg    SLEntryPtr    entry;
32022944501Smrg    int           i;
32122944501Smrg
32222944501Smrg    if (list->magic != SL_LIST_MAGIC) {
32322944501Smrg	printf("Bad magic: 0x%08lx (expected 0x%08lx)\n",
32422944501Smrg	       list->magic, SL_LIST_MAGIC);
32522944501Smrg	return;
32622944501Smrg    }
32722944501Smrg
32822944501Smrg    printf("Level = %d, count = %d\n", list->level, list->count);
32922944501Smrg    for (entry = list->head; entry; entry = entry->forward[0]) {
33022944501Smrg	if (entry->magic != SL_ENTRY_MAGIC) {
33122944501Smrg	    printf("Bad magic: 0x%08lx (expected 0x%08lx)\n",
33222944501Smrg		   list->magic, SL_ENTRY_MAGIC);
33322944501Smrg	}
33422944501Smrg	printf("\nEntry %p <0x%08lx, %p> has %2d levels\n",
33522944501Smrg	       entry, entry->key, entry->value, entry->levels);
33622944501Smrg	for (i = 0; i < entry->levels; i++) {
33722944501Smrg	    if (entry->forward[i]) {
33822944501Smrg		printf("   %2d: %p <0x%08lx, %p>\n",
33922944501Smrg		       i,
34022944501Smrg		       entry->forward[i],
34122944501Smrg		       entry->forward[i]->key,
34222944501Smrg		       entry->forward[i]->value);
34322944501Smrg	    } else {
34422944501Smrg		printf("   %2d: %p\n", i, entry->forward[i]);
34522944501Smrg	    }
34622944501Smrg	}
34722944501Smrg    }
34822944501Smrg}
34922944501Smrg
35022944501Smrg#if SL_MAIN
35122944501Smrgstatic void print(SkipListPtr list)
35222944501Smrg{
35322944501Smrg    unsigned long key;
35422944501Smrg    void          *value;
35522944501Smrg
35622944501Smrg    if (drmSLFirst(list, &key, &value)) {
35722944501Smrg	do {
35822944501Smrg	    printf("key = %5lu, value = %p\n", key, value);
35922944501Smrg	} while (drmSLNext(list, &key, &value));
36022944501Smrg    }
36122944501Smrg}
36222944501Smrg
36322944501Smrgstatic double do_time(int size, int iter)
36422944501Smrg{
36522944501Smrg    SkipListPtr    list;
36622944501Smrg    int            i, j;
36722944501Smrg    unsigned long  keys[1000000];
36822944501Smrg    unsigned long  previous;
36922944501Smrg    unsigned long  key;
37022944501Smrg    void           *value;
37122944501Smrg    struct timeval start, stop;
37222944501Smrg    double         usec;
37322944501Smrg    SL_RANDOM_DECL;
37422944501Smrg
37522944501Smrg    SL_RANDOM_INIT(12345);
37622944501Smrg
37722944501Smrg    list = drmSLCreate();
37822944501Smrg
37922944501Smrg    for (i = 0; i < size; i++) {
38022944501Smrg	keys[i] = SL_RANDOM;
38122944501Smrg	drmSLInsert(list, keys[i], NULL);
38222944501Smrg    }
38322944501Smrg
38422944501Smrg    previous = 0;
38522944501Smrg    if (drmSLFirst(list, &key, &value)) {
38622944501Smrg	do {
38722944501Smrg	    if (key <= previous) {
38822944501Smrg		printf( "%lu !< %lu\n", previous, key);
38922944501Smrg	    }
39022944501Smrg	    previous = key;
39122944501Smrg	} while (drmSLNext(list, &key, &value));
39222944501Smrg    }
39322944501Smrg
39422944501Smrg    gettimeofday(&start, NULL);
39522944501Smrg    for (j = 0; j < iter; j++) {
39622944501Smrg	for (i = 0; i < size; i++) {
39722944501Smrg	    if (drmSLLookup(list, keys[i], &value))
39822944501Smrg		printf("Error %lu %d\n", keys[i], i);
39922944501Smrg	}
40022944501Smrg    }
40122944501Smrg    gettimeofday(&stop, NULL);
40222944501Smrg
40322944501Smrg    usec = (double)(stop.tv_sec * 1000000 + stop.tv_usec
40422944501Smrg		    - start.tv_sec * 1000000 - start.tv_usec) / (size * iter);
40522944501Smrg
40622944501Smrg    printf("%0.2f microseconds for list length %d\n", usec, size);
40722944501Smrg
40822944501Smrg    drmSLDestroy(list);
40922944501Smrg
41022944501Smrg    return usec;
41122944501Smrg}
41222944501Smrg
41322944501Smrgstatic void print_neighbors(void *list, unsigned long key)
41422944501Smrg{
41522944501Smrg    unsigned long prev_key = 0;
41622944501Smrg    unsigned long next_key = 0;
41722944501Smrg    void          *prev_value;
41822944501Smrg    void          *next_value;
41922944501Smrg    int           retval;
42022944501Smrg
42122944501Smrg    retval = drmSLLookupNeighbors(list, key,
42222944501Smrg				  &prev_key, &prev_value,
42322944501Smrg				  &next_key, &next_value);
42422944501Smrg    printf("Neighbors of %5lu: %d %5lu %5lu\n",
42522944501Smrg	   key, retval, prev_key, next_key);
42622944501Smrg}
42722944501Smrg
42822944501Smrgint main(void)
42922944501Smrg{
43022944501Smrg    SkipListPtr    list;
43122944501Smrg    double         usec, usec2, usec3, usec4;
43222944501Smrg
43322944501Smrg    list = drmSLCreate();
43422944501Smrg    printf( "list at %p\n", list);
43522944501Smrg
43622944501Smrg    print(list);
43722944501Smrg    printf("\n==============================\n\n");
43822944501Smrg
43922944501Smrg    drmSLInsert(list, 123, NULL);
44022944501Smrg    drmSLInsert(list, 213, NULL);
44122944501Smrg    drmSLInsert(list, 50, NULL);
44222944501Smrg    print(list);
44322944501Smrg    printf("\n==============================\n\n");
44422944501Smrg
44522944501Smrg    print_neighbors(list, 0);
44622944501Smrg    print_neighbors(list, 50);
44722944501Smrg    print_neighbors(list, 51);
44822944501Smrg    print_neighbors(list, 123);
44922944501Smrg    print_neighbors(list, 200);
45022944501Smrg    print_neighbors(list, 213);
45122944501Smrg    print_neighbors(list, 256);
45222944501Smrg    printf("\n==============================\n\n");
45322944501Smrg
45422944501Smrg    drmSLDelete(list, 50);
45522944501Smrg    print(list);
45622944501Smrg    printf("\n==============================\n\n");
45722944501Smrg
45822944501Smrg    drmSLDump(list);
45922944501Smrg    drmSLDestroy(list);
46022944501Smrg    printf("\n==============================\n\n");
46122944501Smrg
46222944501Smrg    usec  = do_time(100, 10000);
46322944501Smrg    usec2 = do_time(1000, 500);
46422944501Smrg    printf("Table size increased by %0.2f, search time increased by %0.2f\n",
46522944501Smrg	   1000.0/100.0, usec2 / usec);
46622944501Smrg
46722944501Smrg    usec3 = do_time(10000, 50);
46822944501Smrg    printf("Table size increased by %0.2f, search time increased by %0.2f\n",
46922944501Smrg	   10000.0/100.0, usec3 / usec);
47022944501Smrg
47122944501Smrg    usec4 = do_time(100000, 4);
47222944501Smrg    printf("Table size increased by %0.2f, search time increased by %0.2f\n",
47322944501Smrg	   100000.0/100.0, usec4 / usec);
47422944501Smrg
47522944501Smrg    return 0;
47622944501Smrg}
47722944501Smrg#endif
478