1d722e3fbSopenharmony_ci/* xf86drmSL.c -- Skip list support 2d722e3fbSopenharmony_ci * Created: Mon May 10 09:28:13 1999 by faith@precisioninsight.com 3d722e3fbSopenharmony_ci * 4d722e3fbSopenharmony_ci * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 5d722e3fbSopenharmony_ci * All Rights Reserved. 6d722e3fbSopenharmony_ci * 7d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 8d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 9d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation 10d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 12d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 13d722e3fbSopenharmony_ci * 14d722e3fbSopenharmony_ci * The above copyright notice and this permission notice (including the next 15d722e3fbSopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 16d722e3fbSopenharmony_ci * Software. 17d722e3fbSopenharmony_ci * 18d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21d722e3fbSopenharmony_ci * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22d722e3fbSopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23d722e3fbSopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24d722e3fbSopenharmony_ci * DEALINGS IN THE SOFTWARE. 25d722e3fbSopenharmony_ci * 26d722e3fbSopenharmony_ci * Authors: Rickard E. (Rik) Faith <faith@valinux.com> 27d722e3fbSopenharmony_ci * 28d722e3fbSopenharmony_ci * DESCRIPTION 29d722e3fbSopenharmony_ci * 30d722e3fbSopenharmony_ci * This file contains a straightforward skip list implementation.n 31d722e3fbSopenharmony_ci * 32d722e3fbSopenharmony_ci * FUTURE ENHANCEMENTS 33d722e3fbSopenharmony_ci * 34d722e3fbSopenharmony_ci * REFERENCES 35d722e3fbSopenharmony_ci * 36d722e3fbSopenharmony_ci * [Pugh90] William Pugh. Skip Lists: A Probabilistic Alternative to 37d722e3fbSopenharmony_ci * Balanced Trees. CACM 33(6), June 1990, pp. 668-676. 38d722e3fbSopenharmony_ci * 39d722e3fbSopenharmony_ci */ 40d722e3fbSopenharmony_ci 41d722e3fbSopenharmony_ci#include <stdio.h> 42d722e3fbSopenharmony_ci#include <stdlib.h> 43d722e3fbSopenharmony_ci 44d722e3fbSopenharmony_ci#include "libdrm_macros.h" 45d722e3fbSopenharmony_ci#include "xf86drm.h" 46d722e3fbSopenharmony_ci 47d722e3fbSopenharmony_ci#define SL_LIST_MAGIC 0xfacade00LU 48d722e3fbSopenharmony_ci#define SL_ENTRY_MAGIC 0x00fab1edLU 49d722e3fbSopenharmony_ci#define SL_FREED_MAGIC 0xdecea5edLU 50d722e3fbSopenharmony_ci#define SL_MAX_LEVEL 16 51d722e3fbSopenharmony_ci#define SL_RANDOM_SEED 0xc01055a1LU 52d722e3fbSopenharmony_ci 53d722e3fbSopenharmony_ci#define SL_RANDOM_DECL static void *state = NULL 54d722e3fbSopenharmony_ci#define SL_RANDOM_INIT(seed) if (!state) state = drmRandomCreate(seed) 55d722e3fbSopenharmony_ci#define SL_RANDOM drmRandom(state) 56d722e3fbSopenharmony_ci 57d722e3fbSopenharmony_citypedef struct SLEntry { 58d722e3fbSopenharmony_ci unsigned long magic; /* SL_ENTRY_MAGIC */ 59d722e3fbSopenharmony_ci unsigned long key; 60d722e3fbSopenharmony_ci void *value; 61d722e3fbSopenharmony_ci int levels; 62d722e3fbSopenharmony_ci struct SLEntry *forward[1]; /* variable sized array */ 63d722e3fbSopenharmony_ci} SLEntry, *SLEntryPtr; 64d722e3fbSopenharmony_ci 65d722e3fbSopenharmony_citypedef struct SkipList { 66d722e3fbSopenharmony_ci unsigned long magic; /* SL_LIST_MAGIC */ 67d722e3fbSopenharmony_ci int level; 68d722e3fbSopenharmony_ci int count; 69d722e3fbSopenharmony_ci SLEntryPtr head; 70d722e3fbSopenharmony_ci SLEntryPtr p0; /* Position for iteration */ 71d722e3fbSopenharmony_ci} SkipList, *SkipListPtr; 72d722e3fbSopenharmony_ci 73d722e3fbSopenharmony_cistatic SLEntryPtr SLCreateEntry(int max_level, unsigned long key, void *value) 74d722e3fbSopenharmony_ci{ 75d722e3fbSopenharmony_ci SLEntryPtr entry; 76d722e3fbSopenharmony_ci 77d722e3fbSopenharmony_ci if (max_level < 0 || max_level > SL_MAX_LEVEL) max_level = SL_MAX_LEVEL; 78d722e3fbSopenharmony_ci 79d722e3fbSopenharmony_ci entry = drmMalloc(sizeof(*entry) 80d722e3fbSopenharmony_ci + (max_level + 1) * sizeof(entry->forward[0])); 81d722e3fbSopenharmony_ci if (!entry) return NULL; 82d722e3fbSopenharmony_ci entry->magic = SL_ENTRY_MAGIC; 83d722e3fbSopenharmony_ci entry->key = key; 84d722e3fbSopenharmony_ci entry->value = value; 85d722e3fbSopenharmony_ci entry->levels = max_level + 1; 86d722e3fbSopenharmony_ci 87d722e3fbSopenharmony_ci return entry; 88d722e3fbSopenharmony_ci} 89d722e3fbSopenharmony_ci 90d722e3fbSopenharmony_cistatic int SLRandomLevel(void) 91d722e3fbSopenharmony_ci{ 92d722e3fbSopenharmony_ci int level = 1; 93d722e3fbSopenharmony_ci SL_RANDOM_DECL; 94d722e3fbSopenharmony_ci 95d722e3fbSopenharmony_ci SL_RANDOM_INIT(SL_RANDOM_SEED); 96d722e3fbSopenharmony_ci 97d722e3fbSopenharmony_ci while ((SL_RANDOM & 0x01) && level < SL_MAX_LEVEL) ++level; 98d722e3fbSopenharmony_ci return level; 99d722e3fbSopenharmony_ci} 100d722e3fbSopenharmony_ci 101d722e3fbSopenharmony_cidrm_public void *drmSLCreate(void) 102d722e3fbSopenharmony_ci{ 103d722e3fbSopenharmony_ci SkipListPtr list; 104d722e3fbSopenharmony_ci int i; 105d722e3fbSopenharmony_ci 106d722e3fbSopenharmony_ci list = drmMalloc(sizeof(*list)); 107d722e3fbSopenharmony_ci if (!list) return NULL; 108d722e3fbSopenharmony_ci list->magic = SL_LIST_MAGIC; 109d722e3fbSopenharmony_ci list->level = 0; 110d722e3fbSopenharmony_ci list->head = SLCreateEntry(SL_MAX_LEVEL, 0, NULL); 111d722e3fbSopenharmony_ci list->count = 0; 112d722e3fbSopenharmony_ci 113d722e3fbSopenharmony_ci for (i = 0; i <= SL_MAX_LEVEL; i++) list->head->forward[i] = NULL; 114d722e3fbSopenharmony_ci 115d722e3fbSopenharmony_ci return list; 116d722e3fbSopenharmony_ci} 117d722e3fbSopenharmony_ci 118d722e3fbSopenharmony_cidrm_public int drmSLDestroy(void *l) 119d722e3fbSopenharmony_ci{ 120d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 121d722e3fbSopenharmony_ci SLEntryPtr entry; 122d722e3fbSopenharmony_ci SLEntryPtr next; 123d722e3fbSopenharmony_ci 124d722e3fbSopenharmony_ci if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ 125d722e3fbSopenharmony_ci 126d722e3fbSopenharmony_ci for (entry = list->head; entry; entry = next) { 127d722e3fbSopenharmony_ci if (entry->magic != SL_ENTRY_MAGIC) return -1; /* Bad magic */ 128d722e3fbSopenharmony_ci next = entry->forward[0]; 129d722e3fbSopenharmony_ci entry->magic = SL_FREED_MAGIC; 130d722e3fbSopenharmony_ci drmFree(entry); 131d722e3fbSopenharmony_ci } 132d722e3fbSopenharmony_ci 133d722e3fbSopenharmony_ci list->magic = SL_FREED_MAGIC; 134d722e3fbSopenharmony_ci drmFree(list); 135d722e3fbSopenharmony_ci return 0; 136d722e3fbSopenharmony_ci} 137d722e3fbSopenharmony_ci 138d722e3fbSopenharmony_cistatic SLEntryPtr SLLocate(void *l, unsigned long key, SLEntryPtr *update) 139d722e3fbSopenharmony_ci{ 140d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 141d722e3fbSopenharmony_ci SLEntryPtr entry; 142d722e3fbSopenharmony_ci int i; 143d722e3fbSopenharmony_ci 144d722e3fbSopenharmony_ci if (list->magic != SL_LIST_MAGIC) return NULL; 145d722e3fbSopenharmony_ci 146d722e3fbSopenharmony_ci for (i = list->level, entry = list->head; i >= 0; i--) { 147d722e3fbSopenharmony_ci while (entry->forward[i] && entry->forward[i]->key < key) 148d722e3fbSopenharmony_ci entry = entry->forward[i]; 149d722e3fbSopenharmony_ci update[i] = entry; 150d722e3fbSopenharmony_ci } 151d722e3fbSopenharmony_ci 152d722e3fbSopenharmony_ci return entry->forward[0]; 153d722e3fbSopenharmony_ci} 154d722e3fbSopenharmony_ci 155d722e3fbSopenharmony_cidrm_public int drmSLInsert(void *l, unsigned long key, void *value) 156d722e3fbSopenharmony_ci{ 157d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 158d722e3fbSopenharmony_ci SLEntryPtr entry; 159d722e3fbSopenharmony_ci SLEntryPtr update[SL_MAX_LEVEL + 1]; 160d722e3fbSopenharmony_ci int level; 161d722e3fbSopenharmony_ci int i; 162d722e3fbSopenharmony_ci 163d722e3fbSopenharmony_ci if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ 164d722e3fbSopenharmony_ci 165d722e3fbSopenharmony_ci entry = SLLocate(list, key, update); 166d722e3fbSopenharmony_ci 167d722e3fbSopenharmony_ci if (entry && entry->key == key) return 1; /* Already in list */ 168d722e3fbSopenharmony_ci 169d722e3fbSopenharmony_ci 170d722e3fbSopenharmony_ci level = SLRandomLevel(); 171d722e3fbSopenharmony_ci if (level > list->level) { 172d722e3fbSopenharmony_ci level = ++list->level; 173d722e3fbSopenharmony_ci update[level] = list->head; 174d722e3fbSopenharmony_ci } 175d722e3fbSopenharmony_ci 176d722e3fbSopenharmony_ci entry = SLCreateEntry(level, key, value); 177d722e3fbSopenharmony_ci 178d722e3fbSopenharmony_ci /* Fix up forward pointers */ 179d722e3fbSopenharmony_ci for (i = 0; i <= level; i++) { 180d722e3fbSopenharmony_ci entry->forward[i] = update[i]->forward[i]; 181d722e3fbSopenharmony_ci update[i]->forward[i] = entry; 182d722e3fbSopenharmony_ci } 183d722e3fbSopenharmony_ci 184d722e3fbSopenharmony_ci ++list->count; 185d722e3fbSopenharmony_ci return 0; /* Added to table */ 186d722e3fbSopenharmony_ci} 187d722e3fbSopenharmony_ci 188d722e3fbSopenharmony_cidrm_public int drmSLDelete(void *l, unsigned long key) 189d722e3fbSopenharmony_ci{ 190d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 191d722e3fbSopenharmony_ci SLEntryPtr update[SL_MAX_LEVEL + 1]; 192d722e3fbSopenharmony_ci SLEntryPtr entry; 193d722e3fbSopenharmony_ci int i; 194d722e3fbSopenharmony_ci 195d722e3fbSopenharmony_ci if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ 196d722e3fbSopenharmony_ci 197d722e3fbSopenharmony_ci entry = SLLocate(list, key, update); 198d722e3fbSopenharmony_ci 199d722e3fbSopenharmony_ci if (!entry || entry->key != key) return 1; /* Not found */ 200d722e3fbSopenharmony_ci 201d722e3fbSopenharmony_ci /* Fix up forward pointers */ 202d722e3fbSopenharmony_ci for (i = 0; i <= list->level; i++) { 203d722e3fbSopenharmony_ci if (update[i]->forward[i] == entry) 204d722e3fbSopenharmony_ci update[i]->forward[i] = entry->forward[i]; 205d722e3fbSopenharmony_ci } 206d722e3fbSopenharmony_ci 207d722e3fbSopenharmony_ci entry->magic = SL_FREED_MAGIC; 208d722e3fbSopenharmony_ci drmFree(entry); 209d722e3fbSopenharmony_ci 210d722e3fbSopenharmony_ci while (list->level && !list->head->forward[list->level]) --list->level; 211d722e3fbSopenharmony_ci --list->count; 212d722e3fbSopenharmony_ci return 0; 213d722e3fbSopenharmony_ci} 214d722e3fbSopenharmony_ci 215d722e3fbSopenharmony_cidrm_public int drmSLLookup(void *l, unsigned long key, void **value) 216d722e3fbSopenharmony_ci{ 217d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 218d722e3fbSopenharmony_ci SLEntryPtr update[SL_MAX_LEVEL + 1]; 219d722e3fbSopenharmony_ci SLEntryPtr entry; 220d722e3fbSopenharmony_ci 221d722e3fbSopenharmony_ci entry = SLLocate(list, key, update); 222d722e3fbSopenharmony_ci 223d722e3fbSopenharmony_ci if (entry && entry->key == key) { 224d722e3fbSopenharmony_ci *value = entry; 225d722e3fbSopenharmony_ci return 0; 226d722e3fbSopenharmony_ci } 227d722e3fbSopenharmony_ci *value = NULL; 228d722e3fbSopenharmony_ci return -1; 229d722e3fbSopenharmony_ci} 230d722e3fbSopenharmony_ci 231d722e3fbSopenharmony_cidrm_public int drmSLLookupNeighbors(void *l, unsigned long key, 232d722e3fbSopenharmony_ci unsigned long *prev_key, void **prev_value, 233d722e3fbSopenharmony_ci unsigned long *next_key, void **next_value) 234d722e3fbSopenharmony_ci{ 235d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 236d722e3fbSopenharmony_ci SLEntryPtr update[SL_MAX_LEVEL + 1] = {0}; 237d722e3fbSopenharmony_ci int retcode = 0; 238d722e3fbSopenharmony_ci 239d722e3fbSopenharmony_ci SLLocate(list, key, update); 240d722e3fbSopenharmony_ci 241d722e3fbSopenharmony_ci *prev_key = *next_key = key; 242d722e3fbSopenharmony_ci *prev_value = *next_value = NULL; 243d722e3fbSopenharmony_ci 244d722e3fbSopenharmony_ci if (update[0]) { 245d722e3fbSopenharmony_ci *prev_key = update[0]->key; 246d722e3fbSopenharmony_ci *prev_value = update[0]->value; 247d722e3fbSopenharmony_ci ++retcode; 248d722e3fbSopenharmony_ci if (update[0]->forward[0]) { 249d722e3fbSopenharmony_ci *next_key = update[0]->forward[0]->key; 250d722e3fbSopenharmony_ci *next_value = update[0]->forward[0]->value; 251d722e3fbSopenharmony_ci ++retcode; 252d722e3fbSopenharmony_ci } 253d722e3fbSopenharmony_ci } 254d722e3fbSopenharmony_ci return retcode; 255d722e3fbSopenharmony_ci} 256d722e3fbSopenharmony_ci 257d722e3fbSopenharmony_cidrm_public int drmSLNext(void *l, unsigned long *key, void **value) 258d722e3fbSopenharmony_ci{ 259d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 260d722e3fbSopenharmony_ci SLEntryPtr entry; 261d722e3fbSopenharmony_ci 262d722e3fbSopenharmony_ci if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ 263d722e3fbSopenharmony_ci 264d722e3fbSopenharmony_ci entry = list->p0; 265d722e3fbSopenharmony_ci 266d722e3fbSopenharmony_ci if (entry) { 267d722e3fbSopenharmony_ci list->p0 = entry->forward[0]; 268d722e3fbSopenharmony_ci *key = entry->key; 269d722e3fbSopenharmony_ci *value = entry->value; 270d722e3fbSopenharmony_ci return 1; 271d722e3fbSopenharmony_ci } 272d722e3fbSopenharmony_ci list->p0 = NULL; 273d722e3fbSopenharmony_ci return 0; 274d722e3fbSopenharmony_ci} 275d722e3fbSopenharmony_ci 276d722e3fbSopenharmony_cidrm_public int drmSLFirst(void *l, unsigned long *key, void **value) 277d722e3fbSopenharmony_ci{ 278d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 279d722e3fbSopenharmony_ci 280d722e3fbSopenharmony_ci if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ 281d722e3fbSopenharmony_ci 282d722e3fbSopenharmony_ci list->p0 = list->head->forward[0]; 283d722e3fbSopenharmony_ci return drmSLNext(list, key, value); 284d722e3fbSopenharmony_ci} 285d722e3fbSopenharmony_ci 286d722e3fbSopenharmony_ci/* Dump internal data structures for debugging. */ 287d722e3fbSopenharmony_cidrm_public void drmSLDump(void *l) 288d722e3fbSopenharmony_ci{ 289d722e3fbSopenharmony_ci SkipListPtr list = (SkipListPtr)l; 290d722e3fbSopenharmony_ci SLEntryPtr entry; 291d722e3fbSopenharmony_ci int i; 292d722e3fbSopenharmony_ci 293d722e3fbSopenharmony_ci if (list->magic != SL_LIST_MAGIC) { 294d722e3fbSopenharmony_ci printf("Bad magic: 0x%08lx (expected 0x%08lx)\n", 295d722e3fbSopenharmony_ci list->magic, SL_LIST_MAGIC); 296d722e3fbSopenharmony_ci return; 297d722e3fbSopenharmony_ci } 298d722e3fbSopenharmony_ci 299d722e3fbSopenharmony_ci printf("Level = %d, count = %d\n", list->level, list->count); 300d722e3fbSopenharmony_ci for (entry = list->head; entry; entry = entry->forward[0]) { 301d722e3fbSopenharmony_ci if (entry->magic != SL_ENTRY_MAGIC) { 302d722e3fbSopenharmony_ci printf("Bad magic: 0x%08lx (expected 0x%08lx)\n", 303d722e3fbSopenharmony_ci list->magic, SL_ENTRY_MAGIC); 304d722e3fbSopenharmony_ci } 305d722e3fbSopenharmony_ci printf("\nEntry %p <0x%08lx, %p> has %2d levels\n", 306d722e3fbSopenharmony_ci entry, entry->key, entry->value, entry->levels); 307d722e3fbSopenharmony_ci for (i = 0; i < entry->levels; i++) { 308d722e3fbSopenharmony_ci if (entry->forward[i]) { 309d722e3fbSopenharmony_ci printf(" %2d: %p <0x%08lx, %p>\n", 310d722e3fbSopenharmony_ci i, 311d722e3fbSopenharmony_ci entry->forward[i], 312d722e3fbSopenharmony_ci entry->forward[i]->key, 313d722e3fbSopenharmony_ci entry->forward[i]->value); 314d722e3fbSopenharmony_ci } else { 315d722e3fbSopenharmony_ci printf(" %2d: %p\n", i, entry->forward[i]); 316d722e3fbSopenharmony_ci } 317d722e3fbSopenharmony_ci } 318d722e3fbSopenharmony_ci } 319d722e3fbSopenharmony_ci} 320