/* * Copyright (c) 2003 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include "table.h" #define DEFAULT_SIZE 8191 typedef struct table_node_s { char *key; uint32_t nkey; void *datum; struct table_node_s *next; } table_node_t; typedef struct __table_private { uint32_t bucket_count; table_node_t **bucket; } table_private_t; typedef struct { uint32_t bucket_index; table_node_t *node; } table_traverse_t; typedef struct __list_private { struct __list_private *prev; struct __list_private *next; uint32_t refcount; void *data; } list_private_t; table_t * _nc_table_new(uint32_t n) { table_private_t *t; t = (table_t *)malloc(sizeof(table_t)); if (t == NULL) return NULL; if (n == 0) n = DEFAULT_SIZE; t->bucket_count = n; t->bucket = (table_node_t **)calloc(t->bucket_count, sizeof(sizeof(table_node_t *))); if (t->bucket == NULL) { free(t); return NULL; } return (table_t *)t; } static uint32_t hash_key(int size, const char *key) { uint32_t v; for (v = 0; *key != NULL; *key++) { v = (v << 1) ^ (v ^ *key); } v %= size; return v; } static uint32_t hash_nkey(int size, uint32_t key) { return (key % size); } void * _nc_table_find(table_t *tin, const char *key) { table_private_t *t; table_node_t *n; uint32_t b; if (tin == NULL) return NULL; if (key == NULL) return NULL; t = (table_private_t *)tin; b = hash_key(t->bucket_count, key); for (n = t->bucket[b]; n != NULL; n = n->next) { if ((n->key != NULL) && (!strcmp(key, n->key))) return n->datum; } return NULL; } void * _nc_table_find_n(table_t *tin, uint32_t key) { table_private_t *t; table_node_t *n; uint32_t b; if (tin == NULL) return NULL; t = (table_private_t *)tin; b = hash_nkey(t->bucket_count, key); for (n = t->bucket[b]; n != NULL; n = n->next) { if ((n->nkey != (uint32_t)-1) && (key == n->nkey)) return n->datum; } return NULL; } void _nc_table_insert(table_t *tin, const char *key, void *datum) { table_private_t *t; table_node_t *n; uint32_t b; if (tin == NULL) return; if (key == NULL) return; if (datum == NULL) return; t = (table_private_t *)tin; b = hash_key(t->bucket_count, key); n = (table_node_t *)malloc(sizeof(table_node_t)); n->key = strdup(key); n->nkey = (uint32_t)-1; n->datum = datum; n->next = t->bucket[b]; t->bucket[b] = n; } void _nc_table_insert_n(table_t *tin, uint32_t key, void *datum) { table_private_t *t; table_node_t *n; uint32_t b; if (tin == NULL) return; if (datum == NULL) return; t = (table_private_t *)tin; b = hash_nkey(t->bucket_count, key); n = (table_node_t *)malloc(sizeof(table_node_t)); n->key = NULL; n->nkey = key; n->datum = datum; n->next = t->bucket[b]; t->bucket[b] = n; } void _nc_table_delete(table_t *tin, const char *key) { table_private_t *t; table_node_t *n, *p; uint32_t b; if (tin == NULL) return; if (key == NULL) return; t = (table_private_t *)tin; b = hash_key(t->bucket_count, key); p = NULL; for (n = t->bucket[b]; n != NULL; n = n->next) { if ((n->key != NULL) && (!strcmp(key, n->key))) { if (p == NULL) t->bucket[b] = n->next; else p->next = n->next; if (n->key != NULL) free(n->key); free(n); return; } p = n; } } void _nc_table_delete_n(table_t *tin, uint32_t key) { table_private_t *t; table_node_t *n, *p; uint32_t b; if (tin == NULL) return; t = (table_private_t *)tin; b = hash_nkey(t->bucket_count, key); p = NULL; for (n = t->bucket[b]; n != NULL; n = n->next) { if ((n->nkey != (uint32_t)-1) && (key == n->nkey)) { if (p == NULL) t->bucket[b] = n->next; else p->next = n->next; if (n->key != NULL) free(n->key); free(n); return; } p = n; } } void * _nc_table_traverse_start(table_t *tin) { table_traverse_t *tt; table_private_t *t; uint32_t b; if (tin == NULL) return NULL; t = (table_private_t *)tin; if (t->bucket_count == 0) return NULL; for (b = 0; b < t->bucket_count; b++) { if (t->bucket[b] != NULL) { tt = (table_traverse_t *)malloc(sizeof(table_traverse_t)); if (tt == NULL) return NULL; tt->bucket_index = b; tt->node = t->bucket[b]; return (void *)tt; } } return NULL; } void * _nc_table_traverse(table_t *tin, void *ttin) { table_private_t *t; table_traverse_t *tt; void *datum; uint32_t b; if (tin == NULL) return NULL; if (ttin == NULL) return NULL; t = (table_private_t *)tin; tt = (table_traverse_t *)ttin; if (tt->node == NULL) return NULL; datum = tt->node->datum; tt->node = tt->node->next; if (tt->node != NULL) return datum; for (b = tt->bucket_index + 1; b < t->bucket_count; b++) { if (t->bucket[b] != NULL) { tt->bucket_index = b; tt->node = t->bucket[b]; return datum; } } tt->bucket_index = b; tt->node = NULL; return datum; } void _nc_table_traverse_end(table_t *tin, void *ttin) { if (ttin == NULL) return; free(ttin); } void _nc_table_free(table_t *tin) { table_private_t *t; table_node_t *n, *x; uint32_t b; if (tin == NULL) return; t = (table_private_t *)tin; for (b = 0; b < t->bucket_count; b++) { x = NULL; for (n = t->bucket[b]; n != NULL; n = x) { x = n->next; free(n->key); free(n); } } free(t->bucket); free(t); } /* Linked List */ /* * Make a new node */ list_t * _nc_list_new(void *d) { list_t *n; n = (list_t *)calloc(1, sizeof(list_t)); if (n == NULL) return NULL; n->refcount = 1; n->data = d; return n; } /* * Release a node */ void _nc_list_release(list_t *l) { if (l == NULL) return; l->refcount--; if (l->refcount > 0) return; free(l); } /* * Retain a node */ list_t * _nc_list_retain(list_t *l) { if (l == NULL) return NULL; l->refcount++; return l; } /* * Retain a list */ list_t * _nc_list_retain_list(list_t *l) { list_t *n; for (n = l; n != NULL; n = n->next) n->refcount++; return l; } /* * Get previous node */ list_t * _nc_list_prev(list_t *l) { if (l == NULL) return NULL; return l->prev; } /* * Get next node */ list_t * _nc_list_next(list_t *l) { if (l == NULL) return NULL; return l->next; } /* * Get head (first node) of list */ list_t * _nc_list_head(list_t *l) { list_t *p; if (l == NULL) return NULL; for (p = l; p->prev != NULL; p = p->prev); return p; } /* * Get tail (last node) of list */ list_t * _nc_list_tail(list_t *l) { list_t *p; if (l == NULL) return NULL; for (p = l; p->next != NULL; p = p->next); return p; } /* * Insert a node in front of another node. * Cuts list if n is NULL. */ list_t * _nc_list_prepend(list_t *l, list_t *n) { if (l == NULL) return n; if (n != NULL) { n->next = l; n->prev = l->prev; } if (l->prev != NULL) l->prev->next = n; l->prev = n; return n; } /* * Append a node after another node. * Cuts list if n is NULL. */ list_t * _nc_list_append(list_t *l, list_t *n) { if (l == NULL) return n; if (n != NULL) { n->prev = l; n->next = l->next; } if (l->next != NULL) n->next->prev = n; l->next = n; return n; } /* * Set next pointer - use with care. */ void _nc_list_set_next(list_t *l, list_t *n) { if (l == NULL) return; l->next = n; } /* * Set prev pointer - use with care. */ void _nc_list_set_prev(list_t *l, list_t *p) { if (l == NULL) return; l->prev = p; } /* * Concatenate two lists. * Returns new head. */ list_t * _nc_list_concat(list_t *a, list_t *b) { list_t *p; if (a == NULL) return b; if (b == NULL) return a; for (p = a; p->next != NULL; p = p->next); p->next = b; b->prev = p; for (p = a; p->prev != NULL; p = p->prev); return p; } uint32_t _nc_list_count(list_t *l) { uint32_t n; list_t *p; n = 0; for (p = l; p != NULL; p = p->next) n++; return n; } void * _nc_list_data(list_t *l) { if (l == NULL) return NULL; return l->data; } void _nc_list_set_data(list_t *l, void *d) { if (l != NULL) l->data = d; } list_t * _nc_list_find(list_t *l, void *d) { list_t *p; if (l == NULL) return NULL; for (p = l; p != NULL; p = p->next) { if (p->data == d) return p; } return NULL; } list_t * _nc_list_find_release(list_t *l, void *d) { list_t *p; if (l == NULL) return NULL; if (l->data == d) { p = l->next; if (p != NULL) p->prev = NULL; _nc_list_release(l); return p; } for (p = l->next; p != NULL; p = p->next) { if (p->data == d) { p->prev->next = p->next; if (p->next != NULL) p->next->prev = p->prev; _nc_list_release(p); return l; } } return l; } list_t * _nc_list_reverse(list_t *l) { list_t *x, *s, *r; if (l == NULL) return NULL; x = l->prev; r = l; s = l->next; while (s != NULL) { s = r->next; r->next = r->prev; r->prev = s; if (s != NULL) r = s; } if (x != NULL) { x->next = r; r->prev = x; } return r; } list_t * _nc_list_extract(list_t *n) { if (n == NULL) return NULL; if (n->prev != NULL) n->prev->next = n->next; if (n->next != NULL) n->next->prev = n->prev; n->prev = NULL; n->next = NULL; return n; } list_t * _nc_list_chop(list_t *l) { list_t *p; if (l == NULL) return NULL; p = l->next; if (p != NULL) p->prev = NULL; _nc_list_release(l); return p; } void _nc_list_release_list(list_t *l) { list_t *p, *n; if (l == NULL) return; if (l->prev != NULL) l->prev->next = NULL; p = l; while (p != NULL) { n = p->next; _nc_list_release(p); p = n; } }