types.c
author Dan Winship <danw@gnome.org>
Thu Feb 07 09:58:48 2008 -0500 (2008-02-07)
changeset 115 26edeea5c95a
child 116 4ec6e2a55c34
permissions -rw-r--r--
split array and hashtable code out into a new file
     1 #include <stdlib.h>
     2 #include <string.h>
     3 
     4 #include "types.h"
     5 
     6 void
     7 array_init(struct array *array)
     8 {
     9 	memset(array, 0, sizeof *array);
    10 }
    11 
    12 void
    13 array_release(struct array *array)
    14 {
    15 	free(array->data);
    16 }
    17 
    18 void *
    19 array_add(struct array *array, int size)
    20 {
    21 	int alloc;
    22 	void *data, *p;
    23 
    24 	if (array->alloc > 0)
    25 		alloc = array->alloc;
    26 	else
    27 		alloc = 16;
    28 
    29 	while (alloc < array->size + size)
    30 		alloc *= 2;
    31 
    32 	if (array->alloc < alloc) {
    33 		data = realloc(array->data, alloc);
    34 		if (data == NULL)
    35 			return 0;
    36 		array->data = data;
    37 		array->alloc = alloc;
    38 	}
    39 
    40 	p = array->data + array->size;
    41 	array->size += size;
    42 
    43 	return p;
    44 }
    45 
    46 
    47 void
    48 hashtable_init(struct hashtable *table, struct array *pool)
    49 {
    50 	array_init(&table->buckets);
    51 	table->pool = pool;
    52 }
    53 
    54 void
    55 hashtable_release(struct hashtable *table)
    56 {
    57 	array_release(&table->buckets);
    58 }
    59 
    60 static unsigned int
    61 hash_string(const char *key)
    62 {
    63 	const char *p;
    64 	unsigned int hash = 0;
    65 
    66 	for (p = key; *p; p++)
    67 		hash = (hash * 617) ^ *p;
    68 
    69 	return hash;
    70 }
    71 
    72 uint32_t
    73 hashtable_lookup(struct hashtable *table, const char *key)
    74 {
    75 	unsigned int mask, start, i;
    76 	uint32_t *b;
    77 	char *pool;
    78 
    79 	pool = table->pool->data;
    80 	mask = table->buckets.alloc - 1;
    81 	start = hash_string(key) * sizeof(uint32_t);
    82 
    83 	for (i = 0; i < table->buckets.alloc; i += sizeof *b) {
    84 		b = table->buckets.data + ((start + i) & mask);
    85 
    86 		if (*b == 0)
    87 			return 0;
    88 
    89 		if (strcmp(key, &pool[*b]) == 0)
    90 			return *b;
    91 	}
    92 
    93 	return 0;
    94 }
    95 
    96 static void
    97 do_insert(struct hashtable *table, uint32_t value)
    98 {
    99 	unsigned int mask, start, i;
   100 	uint32_t *b;
   101 	const char *key;
   102 
   103 	key = (char *) table->pool->data + value;
   104 	mask = table->buckets.alloc - 1;
   105 	start = hash_string(key) * sizeof(uint32_t);
   106 
   107 	for (i = 0; i < table->buckets.alloc; i += sizeof *b) {
   108 		b = table->buckets.data + ((start + i) & mask);
   109 		if (*b == 0) {
   110 			*b = value;
   111 			break;
   112 		}
   113 	}
   114 }
   115 
   116 static uint32_t
   117 add_to_string_pool(struct hashtable *table, const char *key)
   118 {
   119 	int len;
   120 	char *p;
   121 
   122 	len = strlen(key) + 1;
   123 	p = array_add(table->pool, len);
   124 	memcpy(p, key, len);
   125 
   126 	return p - (char *) table->pool->data;
   127 }
   128 
   129 uint32_t
   130 hashtable_insert(struct hashtable *table, const char *key)
   131 {
   132 	uint32_t value, *buckets, *b, *end;
   133 	int alloc;
   134 
   135 	alloc = table->buckets.alloc;
   136 	array_add(&table->buckets, 4 * sizeof *buckets);
   137 	if (alloc != table->buckets.alloc) {
   138 		end = table->buckets.data + alloc;
   139 		memset(end, 0, table->buckets.alloc - alloc);
   140 		for (b = table->buckets.data; b < end; b++) {
   141 			value = *b;
   142 			if (value != 0) {
   143 				*b = 0;
   144 				do_insert(table, value);
   145 			}
   146 		}
   147 	}
   148 
   149 	value = add_to_string_pool(table, key);
   150 	do_insert (table, value);
   151 
   152 	return value;
   153 }
   154 
   155 uint32_t
   156 hashtable_tokenize(struct hashtable *table, const char *string)
   157 {
   158 	uint32_t token;
   159 
   160 	if (string == NULL)
   161 		string = "";
   162 
   163 	token = hashtable_lookup(table, string);
   164 	if (token != 0)
   165 		return token;
   166 
   167 	return hashtable_insert(table, string);
   168 }