Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

rewrite for thread safe

  • Loading branch information...
commit a66c00937bb59d42c5e25b7c9d439f60f676d2cc 1 parent 96062af
@cloudwu authored
Showing with 575 additions and 162 deletions.
  1. +5 −2 Makefile
  2. +1 −1  README
  3. +304 −0 hash.c
  4. +44 −0 hash.h
  5. +126 −156 lua-db.c
  6. +3 −3 test.lua
  7. +92 −0 testhash.c
View
7 Makefile
@@ -2,7 +2,10 @@ linux:
gcc -fPIC -O2 -Wall -o database.so --shared lua-db.c -I/usr/local/include
win32:
- gcc -O2 -Wall -march=i586 -o database.dll --shared lua-db.c -I/usr/local/include -L/usr/local/bin -llua52
+ gcc -O2 -Wall -march=i586 -o database.dll --shared lua-db.c hash.c -I/usr/local/include -L/usr/local/bin -llua52
test:
- gcc -O2 -Wall -o testmt -I/usr/local/include test.c -lpthread -llua -lm -ldl
+ gcc -O2 -Wall -o testmt -I/usr/local/include test.c -lpthread -llua -lm -ldl
+
+hash:
+ gcc -g -Wall -o testhash hash.c testhash.c -I/usr/local/include -L/usr/local/bin -llua52
View
2  README
@@ -1,4 +1,4 @@
-database load data in an unique lua state , and share data among multi-states in the same process .
+database load data in an unique hash table , and share data among multi-states in the same process .
database.open(loader name) -- opens database state.
View
304 hash.c
@@ -0,0 +1,304 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <string.h>
+
+#include "hash.h"
+
+#define STRING_INDEX 1
+
+struct hash_node {
+ uint32_t hash;
+ const char * key;
+ struct data value;
+ int next;
+};
+
+struct hash {
+ int size;
+ struct hash_node * node;
+ int lastfree;
+ char * stringpool;
+ lua_State * temp;
+};
+
+static uint32_t
+calc_hash(const char * str, size_t sz) {
+ uint32_t h = (uint32_t)sz;
+ size_t step = (sz>>5)+1;
+ size_t l1;
+ for (l1=sz; l1>=step; l1-=step) {
+ h = h ^ ((h<<5)+(h>>2)+(uint32_t)str[l1-1]);
+ }
+ return h;
+}
+
+static const char *
+store_string(lua_State *L, const char * str, size_t sz) {
+ lua_pushlstring(L, str, sz);
+ const char * n = lua_tostring(L, -1);
+ lua_pushlightuserdata(L, (void *)n);
+ lua_insert(L, -2);
+ lua_rawset(L, STRING_INDEX);
+ return n;
+}
+
+void
+debug_table(struct hash *h) {
+ lua_State *L = h->temp;
+ lua_pushnil(L);
+ while (lua_next(L, STRING_INDEX) != 0) {
+ printf("%p - %s\n",
+ lua_touserdata(L,-2),
+ lua_tostring(L,-1));
+ lua_pop(L, 1);
+ }
+}
+
+static inline struct hash_node *
+mainposition(struct hash * self, uint32_t hash) {
+ return &self->node[(hash & (self->size - 1 ))];
+}
+
+static struct hash_node *
+findfree(struct hash * self) {
+ while (self->lastfree >= 0) {
+ struct hash_node * n = &self->node[self->lastfree--];
+ if (n->key == NULL) {
+ return n;
+ }
+ }
+ return NULL;
+}
+
+static struct table *
+copy_table(lua_State *L, struct table * from) {
+ struct table * to = malloc(sizeof(*from) + from->size * sizeof(const char *));
+ to->size = from->size;
+ to->array = (const char **)(to + 1);
+ int i;
+ for (i=0;i<to->size;i++) {
+ to->array[i] = store_string(L, from->array[i], strlen(from->array[i]));
+ }
+ return to;
+}
+
+static void
+push_value(struct hash * self, struct hash_node *n , struct data * value, bool copy) {
+ if (copy) {
+ memcpy(&n->value , value, sizeof(*value));
+ return;
+ }
+ n->value.type = value->type;
+ switch(value->type) {
+ case TYPE_NIL:
+ break;
+ case TYPE_BOOLEAN:
+ n->value.v.boolean = value->v.boolean;
+ break;
+ case TYPE_NUMBER:
+ n->value.v.n = value->v.n;
+ break;
+ case TYPE_STRING:
+ case TYPE_FUNCTION:
+ n->value.v.str.str = store_string(self->temp, value->v.str.str, value->v.str.len);
+ n->value.v.str.len = value->v.str.len;
+ break;
+ case TYPE_TABLE:
+ n->value.v.tbl = copy_table(self->temp, value->v.tbl);
+ break;
+ }
+}
+
+static void expend_hash(struct hash * self);
+
+static void
+push_hashkey(struct hash * self , const char * str , uint32_t hash, struct data * value, bool copy) {
+ struct hash_node *mn = mainposition(self,hash);
+ if (mn->key == NULL) {
+ mn->key = str;
+ mn->hash = hash;
+ push_value(self, mn , value , copy);
+ return;
+ }
+ if (mainposition(self, mn->hash) != mn) {
+ const char * tempk = mn->key;
+ uint32_t temph = mn->hash;
+ struct data tempv = mn->value;
+ mn->key = str;
+ mn->hash = hash;
+ push_value(self, mn, value , copy);
+ push_hashkey(self, tempk, temph, &tempv , true);
+ return;
+ }
+ struct hash_node * free = findfree(self);
+ if (free == NULL) {
+ expend_hash(self);
+ push_hashkey(self, str, hash, value , copy);
+ return;
+ }
+ free->key = str;
+ free->hash = hash;
+ push_value(self, free, value, copy);
+ free->next = mn->next;
+ mn->next = free - self->node;
+}
+
+static void
+expend_hash(struct hash * self) {
+ int osize = self->size;
+ struct hash_node * onode = self->node;
+ self->size *= 2;
+ self->lastfree = self->size - 1;
+ self->node = malloc(sizeof(struct hash_node) * self->size);
+ int i;
+ for (i=0;i<self->size;i++) {
+ self->node[i].hash = 0;
+ self->node[i].key = NULL;
+ self->node[i].next = -1;
+ }
+ for (i=0;i<osize;i++) {
+ if (onode[i].key) {
+ push_hashkey(self, onode[i].key, onode[i].hash, &onode[i].value , true);
+ }
+ }
+ free(onode);
+}
+
+void
+hash_push(struct hash * self , const char * key , size_t sz, struct data * value) {
+ const char * str = store_string(self->temp, key, sz);
+ uint32_t hash = calc_hash(str, sz);
+ push_hashkey(self, str, hash, value , false);
+};
+
+struct data *
+hash_search(struct hash * self, const char * key , size_t sz) {
+ uint32_t h = calc_hash(key,sz);
+ struct hash_node * n = &self->node[h & (self->size-1)];
+ for (;;) {
+ if (n->hash == h && memcmp(n->key , key , sz+1)==0) {
+ return &n->value;
+ }
+ if (n->next < 0)
+ return NULL;
+ n = &self->node[n->next];
+ }
+};
+
+static size_t
+sum_string(lua_State *L) {
+ size_t sz = 0;
+ lua_pushnil(L);
+ while (lua_next(L, STRING_INDEX) != 0) {
+ size_t len = 0;
+ lua_tolstring(L , -1 , &len);
+ sz += (len+4) & ~3;
+ lua_pop(L, 1);
+ }
+ return sz;
+}
+
+static void
+copy_string(lua_State *L , char * buffer) {
+ lua_pushnil(L);
+ while (lua_next(L, STRING_INDEX) != 0) {
+ size_t len = 0;
+ const char * str = lua_tolstring(L , -1 , &len);
+ memcpy(buffer, str, len+1);
+ lua_pop(L, 1);
+ lua_pushvalue(L,-1);
+ lua_createtable(L,2,0);
+ lua_pushlightuserdata(L, buffer);
+ lua_rawseti(L, -2, 1);
+ lua_pushinteger(L, len);
+ lua_rawseti(L, -2, 2);
+ lua_rawset(L, STRING_INDEX);
+ buffer += (len+4) & ~3;
+ }
+}
+
+static const char *
+convert_string(lua_State *L, const char * old , size_t *sz) {
+ lua_pushlightuserdata(L, (void *)old);
+ lua_rawget(L, STRING_INDEX);
+ lua_rawgeti(L, -1 , 1);
+ const char * n = (const char *)lua_touserdata(L, -1);
+ lua_pop(L,1);
+ assert(n);
+ if (sz) {
+ lua_rawgeti(L, -1 , 2);
+ *sz = (size_t)lua_tointeger(L, -1);
+ lua_pop(L,1);
+ }
+ lua_pop(L,1);
+ return n;
+}
+
+size_t
+hash_genpool(struct hash * self) {
+ assert(self->stringpool == NULL);
+ lua_State *L = self->temp;
+ size_t sz = sum_string(L);
+ self->stringpool = (char *)malloc(sz);
+ copy_string(L, self->stringpool);
+ int i,j;
+ for (i=0;i<self->size;i++) {
+ struct hash_node * n = &(self->node[i]);
+ if (n->key) {
+ n->key = convert_string(L, n->key,NULL);
+ switch(n->value.type) {
+ case TYPE_STRING:
+ case TYPE_FUNCTION:
+ n->value.v.str.str = convert_string(L, n->value.v.str.str, &(n->value.v.str.len));
+ break;
+ case TYPE_TABLE:
+ sz += sizeof(struct table) + n->value.v.tbl->size * sizeof(const char *);
+ for (j=0;j<n->value.v.tbl->size;j++) {
+ n->value.v.tbl->array[j] = convert_string(L, n->value.v.tbl->array[j],NULL);
+ }
+ break;
+ }
+ }
+ }
+ lua_close(L);
+ self->temp = NULL;
+ return sz + self->size * sizeof(struct hash_node) + sizeof(struct hash);
+}
+
+struct hash *
+hash_new() {
+ struct hash * self = malloc(sizeof(struct hash));
+ self->size = 1;
+ self->node = malloc(sizeof(struct hash_node));
+ self->node[0].hash = 0;
+ self->node[0].key = NULL;
+ self->node[0].next = -1;
+ self->lastfree = 0;
+ self->stringpool = NULL;
+ self->temp = luaL_newstate();
+ lua_gc(self->temp, LUA_GCSTOP, 0);
+ lua_newtable(self->temp);
+
+ return self;
+}
+
+void
+hash_delete(struct hash *self) {
+ int i;
+ for (i=0;i<self->size;i++) {
+ struct hash_node *n = &self->node[i];
+ if (n->key && n->value.type == TYPE_TABLE) {
+ free(n->value.v.tbl);
+ }
+ }
+ free(self->node);
+ free(self->stringpool);
+ if (self->temp) {
+ lua_close(self->temp);
+ }
+}
View
44 hash.h
@@ -0,0 +1,44 @@
+#ifndef LUADB_HASH_H
+#define LUADB_HASH_H
+
+#include <stddef.h>
+#include <lua.h>
+
+#define TYPE_NIL 0
+#define TYPE_NUMBER 1
+#define TYPE_STRING 2
+#define TYPE_BOOLEAN 3
+#define TYPE_FUNCTION 4
+#define TYPE_TABLE 5
+
+
+struct table {
+ int size;
+ const char ** array;
+};
+
+struct bytes {
+ const char * str;
+ size_t len;
+};
+
+struct data {
+ int type;
+ union {
+ struct bytes str;
+ lua_Number n;
+ int boolean;
+ struct table * tbl;
+ } v;
+};
+
+struct hash;
+
+void hash_push(struct hash * self , const char * key , size_t sz, struct data * value);
+struct data * hash_search(struct hash * self, const char * key , size_t sz);
+size_t hash_genpool(struct hash * self);
+struct hash * hash_new();
+void hash_delete(struct hash *self);
+void debug_table(struct hash *h);
+
+#endif
View
282 lua-db.c
@@ -5,16 +5,87 @@
#include <string.h>
#include <assert.h>
+#include "hash.h"
+
+static struct hash * g_Hash = NULL;
+static int g_Init = 0;
+
#define DATA 1
#define INDEX 2
-#define THREAD_MAX 32
-
-static lua_State * g_dbL = NULL;
-static int g_threadcount = 1;
-static __thread int t_threadinit = 0;
-static __thread int t_threadindex = 0;
static void
+push_table(lua_State *L, struct hash * h, const char * key, size_t sz) {
+ size_t n = lua_rawlen(L, -1);
+ struct table tbl;
+ tbl.size = (int)n;
+ const char * data[n];
+ tbl.array = data;
+ int i;
+ for (i=0;i<tbl.size;i++) {
+ lua_rawgeti(L, -1 , i+1);
+ assert(lua_type(L, -1) == LUA_TSTRING);
+ data[i] = lua_tostring(L, -1);
+ lua_pop(L,1);
+ }
+
+ struct data d;
+ d.type = TYPE_TABLE;
+ d.v.tbl = &tbl;
+
+ hash_push(h, key, sz, &d);
+}
+
+static struct hash *
+convert_hash(lua_State *L , size_t *sz) {
+ struct hash * h = hash_new();
+ lua_pushnil(L);
+ struct data d;
+ while (lua_next(L, INDEX) != 0) {
+ if (lua_type(L,-2) == LUA_TSTRING) {
+ size_t sz = 0;
+ const char * key = lua_tolstring(L,-2,&sz);
+ switch(lua_type(L,-1)) {
+ case LUA_TNIL:
+ d.type = TYPE_NIL;
+ hash_push(h, key, sz, &d);
+ break;
+ case LUA_TSTRING:
+ d.type = TYPE_STRING;
+ d.v.str.str = lua_tolstring(L,-1,&d.v.str.len);
+ hash_push(h, key, sz, &d);
+ break;
+ case LUA_TBOOLEAN:
+ d.type = TYPE_BOOLEAN;
+ d.v.boolean = lua_toboolean(L,-1);
+ hash_push(h, key, sz, &d);
+ break;
+ case LUA_TNUMBER:
+ d.type = TYPE_NUMBER;
+ d.v.n = lua_tonumber(L,-1);
+ hash_push(h, key, sz, &d);
+ break;
+ case LUA_TFUNCTION:
+ lua_rawget(L,INDEX);
+ d.type = TYPE_FUNCTION;
+ d.v.str.str = lua_tolstring(L,-1,&d.v.str.len);
+ hash_push(h, key, sz, &d);
+ break;
+ case LUA_TTABLE:
+ push_table(L,h, key, sz);
+ break;
+ default:
+ luaL_error(L , "table has unsupport type : %s", lua_typename(L,lua_type(L,-1)));
+ break;
+ }
+ }
+ lua_pop(L,1);
+ }
+ *sz = hash_genpool(h);
+
+ return h;
+}
+
+static size_t
_init(lua_State *L) {
const char * loader = luaL_checkstring(L,1);
lua_State * dbL = luaL_newstate();
@@ -70,186 +141,85 @@ _init(lua_State *L) {
lua_settop(dbL, 2);
- lua_checkstack(dbL , THREAD_MAX + 2);
- int i;
- for (i=0;i < THREAD_MAX ; i++) {
- lua_State * thread = lua_newthread(dbL);
- lua_checkstack(thread , LUA_MINSTACK);
- lua_pushvalue(dbL , DATA);
- lua_pushvalue(dbL , INDEX);
- lua_xmove(dbL , thread , 2);
- }
-
- lua_remove(dbL , 1);
- lua_remove(dbL , 1);
+ size_t sz = 0;
- lua_gc(dbL, LUA_GCCOLLECT , 0);
- lua_gc(dbL, LUA_GCSTOP, 0);
+ g_Hash = convert_hash(dbL, &sz);
+ lua_close(dbL);
- g_dbL = dbL;
+ return sz;
}
static int
db_open(lua_State *L) {
- int threadinit = __sync_val_compare_and_swap (&t_threadinit, 0, 1);
- if (threadinit == 0) {
- t_threadindex = __sync_fetch_and_add (&g_threadcount, 1);
-
- if (t_threadindex == 1) {
- // init
- _init(L);
- }
-
- __sync_synchronize();
-
- if (t_threadindex > THREAD_MAX) {
- return luaL_error(L, "The number of threads is too a lot");
- }
-
+ int init = __sync_val_compare_and_swap (&g_Init, 0, 1);
+ if (init == 0) {
+ size_t sz = _init(L);
+ lua_pushinteger(L, sz);
+ return 1;
} else {
- while (t_threadindex == 0) {
- __sync_synchronize();
- }
-
- if (g_dbL == NULL) {
+ if (g_Hash == NULL) {
return luaL_error(L, "Global database init failed");
}
-
- lua_State * dbL = lua_tothread(g_dbL, t_threadindex);
- assert(dbL);
-
- const char * loader = luaL_checkstring(L,1);
-
- lua_getfield(dbL, LUA_REGISTRYINDEX , "loader");
- if (lua_type(dbL,-1) != LUA_TSTRING) {
- lua_settop(dbL, 2);
- return luaL_error(L, "loader is not exist in db state");
- }
- const char * db_loader = lua_tostring(dbL,-1);
- if (strcmp(loader,db_loader) != 0) {
- lua_settop(dbL, 2);
- return luaL_error(L, "db state loader is not the same with (%s)", loader);
- }
- lua_settop(dbL, 2);
}
- int mem = lua_gc(g_dbL, LUA_GCCOUNT , 0);
- lua_pushinteger(L, mem);
- lua_pushinteger(L, t_threadindex);
- return 2;
+ return 0;
}
static int
db_get(lua_State *L) {
- lua_State * dbL = lua_tothread(g_dbL, t_threadindex);
- assert(dbL);
-
+ assert(g_Hash);
size_t sz = 0;
const char * key = luaL_checklstring(L,1,&sz);
-
- lua_pushlstring(dbL,key,sz);
- lua_pushvalue(dbL,-1);
- lua_rawget(dbL,INDEX);
-
- int type = lua_type(dbL,-1);
- switch(type) {
- case LUA_TNIL:
- lua_pushnil(L);
- break;
- case LUA_TNUMBER: {
- lua_Number v = lua_tonumber(dbL,-1);
- lua_pushnumber(L,v);
- break;
- }
- case LUA_TSTRING: {
- const char *v = lua_tolstring(dbL,-1,&sz);
- lua_pushlstring(L,v,sz);
- break;
- }
- case LUA_TBOOLEAN: {
- int v = lua_toboolean(dbL,-1);
- lua_pushboolean(L,v);
- break;
+ struct data * d = hash_search(g_Hash , key, sz);
+ if (d==NULL) {
+ luaL_error(L, "%s is not exist", key);
}
- case LUA_TTABLE : {
- void * keyname = (void*)lua_tostring(dbL, -2);
- assert(keyname);
- lua_pushlightuserdata(L, keyname);
- lua_pushliteral(L, "table");
- lua_pop(dbL,2);
+
+ switch(d->type) {
+ case TYPE_NIL:
+ return 0;
+ case TYPE_NUMBER:
+ lua_pushnumber(L, d->v.n);
+ return 1;
+ case TYPE_STRING:
+ lua_pushlstring(L, d->v.str.str, d->v.str.len);
+ return 1;
+ case TYPE_BOOLEAN:
+ lua_pushboolean(L, d->v.boolean);
+ return 1;
+ case TYPE_FUNCTION:
+ lua_pushlightuserdata(L, d);
+ lua_pushliteral(L,"function");
return 2;
- }
- case LUA_TFUNCTION: {
- void * keyname = (void*)lua_tostring(dbL, -2);
- lua_pushlightuserdata(L, keyname);
- lua_pushliteral(L, "function");
- lua_pop(dbL,2);
+ case TYPE_TABLE:
+ lua_pushlightuserdata(L,d);
+ lua_pushliteral(L,"table");
return 2;
}
- default:
- lua_pop(dbL,2);
- luaL_error(L,"unsupported type: %s",lua_typename(dbL, type));
- break;
- }
-
- lua_pop(dbL,2);
- return 1;
+ return luaL_error(L, "unknown type");
}
static int
db_expend(lua_State *L) {
- lua_State * dbL = lua_tothread(g_dbL, t_threadindex);
- int type = lua_type(L,1);
- const char * key = NULL;
- switch (type) {
- case LUA_TLIGHTUSERDATA :
- key = (const char*)lua_touserdata(L,1);
- lua_pushstring(dbL, key);
+ struct data *d = lua_touserdata(L,1);
+ assert(d);
+ int i;
+ switch (d->type) {
+ case TYPE_FUNCTION:
+ lua_pushlstring(L, d->v.str.str, d->v.str.len);
break;
- case LUA_TSTRING : {
- size_t sz = 0;
- key = lua_tolstring(L,1,&sz);
- lua_pushlstring(dbL,key,sz);
+ case TYPE_TABLE:
+ lua_createtable(L, d->v.tbl->size , 0);
+ for (i=0;i<d->v.tbl->size;i++) {
+ lua_pushstring(L, d->v.tbl->array[i]);
+ lua_rawseti(L,-2,i+1);
+ }
break;
- }
default:
- return luaL_error(L, "expand need a string");
- }
- lua_rawget(dbL, INDEX);
- if (lua_isfunction(dbL, -1)) {
- lua_rawget(dbL, INDEX);
- if (!lua_isstring(dbL, -1)) {
- lua_pop(dbL, 1);
- return luaL_error(L, "expand an invalid function %s", key);
- }
- size_t sz = 0;
- const char * code = lua_tolstring(dbL,-1,&sz);
- lua_pushlstring(L, code, sz);
- lua_pop(dbL, 1);
- return 1;
+ return luaL_error(L, "unknown type");
}
-
- if (!lua_istable(dbL, -1)) {
- return luaL_error(L, "%s is not a table or function", key);
- }
-
- int len = lua_rawlen(dbL, -1);
- lua_checkstack(L, 2 + len);
- int i;
- for (i=0;i<len;i++) {
- lua_rawgeti(dbL, -1, i+1);
- size_t sz = 0;
- const char * v = lua_tolstring(dbL, -1 , &sz);
- if (v == NULL) {
- return luaL_error(L, "%s is an invalid table", key);
- }
- lua_pushlstring(L, v , sz);
- lua_pop(dbL,1);
- }
- lua_settop(dbL,2);
-
- return len;
+ return 1;
}
int
View
6 test.lua
@@ -1,7 +1,7 @@
local db = require "database"
-local mem, id = db.open "load.lua"
-print("open:" , mem,id)
+local mem = db.open "load.lua"
+print("open:" , mem)
t = db.get "A"
@@ -12,5 +12,5 @@ end
for i=1,1000 do
local f = db.get "A.B"
- print(id,i,f(),db.get("A."..tostring(math.random(100))))
+ print(i,f(),db.get("A."..tostring(math.random(100))))
end
View
92 testhash.c
@@ -0,0 +1,92 @@
+#include "hash.h"
+#include <string.h>
+#include <stdio.h>
+
+static void
+push_number(struct hash * self, const char *key, lua_Number n) {
+ struct data d;
+ d.type = TYPE_NUMBER;
+ d.v.n = n;
+ hash_push(self, key, strlen(key), &d);
+}
+
+static void
+push_string(struct hash * self, const char *key, const char *value) {
+ struct data d;
+ d.type = TYPE_STRING;
+ d.v.str.str = value;
+ d.v.str.len = strlen(value);
+ hash_push(self, key, strlen(key), &d);
+}
+
+static void
+push_nil(struct hash * self, const char *key) {
+ struct data d;
+ d.type = TYPE_NIL;
+ hash_push(self, key, strlen(key), &d);
+}
+
+static void
+read_hash(struct hash *h, const char *key) {
+ struct data * d = hash_search(h, key, strlen(key));
+ if (d== NULL) {
+ printf("%s = (null)\n",key);
+ } else {
+ printf("%s = ",key);
+ switch(d->type) {
+ case TYPE_NIL:
+ printf("nil");
+ break;
+ case TYPE_NUMBER:
+ printf("%lf",d->v.n);
+ break;
+ case TYPE_FUNCTION:
+ printf("(function)");
+ break;
+ case TYPE_STRING:
+ printf("%s",d->v.str.str);
+ break;
+ case TYPE_TABLE:
+ printf("[table]");
+ break;
+ }
+ printf("\n");
+ }
+}
+
+static void
+test(struct hash *h) {
+ push_number(h, "a" , 1.0);
+ push_string(h, "b" , "hello world");
+ push_nil(h, "c");
+ int i;
+ char buffer[10];
+ for (i=0;i<100;i++) {
+ sprintf(buffer,"%d",i*2);
+ push_number(h,buffer,i);
+ }
+ debug_table(h);
+ hash_genpool(h);
+}
+
+static void
+search(struct hash *h) {
+ read_hash(h,"a");
+ read_hash(h,"b");
+ read_hash(h,"c");
+ int i;
+ char buffer[10];
+ for (i=0;i<100;i++) {
+ sprintf(buffer,"%d",i*2);
+ read_hash(h,buffer);
+ }
+}
+
+int
+main() {
+ struct hash * h = hash_new();
+ test(h);
+ search(h);
+ hash_delete(h);
+ return 0;
+}
Please sign in to comment.
Something went wrong with that request. Please try again.