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