]> rtime.felk.cvut.cz Git - ulut.git/commitdiff
uLUt extended by experimental hash table support.
authorPavel Pisa <pisa@cmp.felk.cvut.cz>
Wed, 30 Dec 2009 21:05:38 +0000 (22:05 +0100)
committerPavel Pisa <pisa@cmp.felk.cvut.cz>
Wed, 30 Dec 2009 21:05:38 +0000 (22:05 +0100)
The code is based on combination of array indexed
by masked value computed by hash function and GAVL
tree for each of array indexes. This combination
should provide good performance even if the hash
function distribute items non-uniformly for same cases.
Solution has drawback in relatively big memory
overhead required in each inserted item to provide
space for tree node.

The API, above all parameters to UL_HASTAB_CUST_NODE_INT_IMP,
will change probably.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
ulut/Makefile.omk
ulut/ul_hashtab.h [new file with mode: 0644]
ulut/ul_hashtabchk.c [new file with mode: 0644]
ulut/ul_hashtabcust.h [new file with mode: 0644]
ulut/ul_hashtabprim.c [new file with mode: 0644]

index 43dca286c59cadc974211247ec89a7c4c900fb63..e74e3bbb99f1ebe3d22ead2c008b3ffe14dd13bb 100644 (file)
@@ -12,7 +12,8 @@ include_HEADERS  = ul_dbuff.h ul_gavl.h ul_gavlcust.h \
               ul_hptree.h ul_htimdefs.h ul_htimer.h ul_itbase.h \
               ul_list.h ul_listbase.h ul_utdefs.h ul_utmalloc.h \
               ul_uniqid.h ul_dbufflog.h ul_log.h ul_logbase.h \
-              ul_logreg.h ul_cbuff.h ul_dqfifo.h
+              ul_logreg.h ul_cbuff.h ul_dqfifo.h ul_hashtab.h \
+              ul_hashtabcust.h
 
 ifneq ($(CONFIG_OC_ULUTMINIMAL),y)
 include_HEADERS  += ul_evcbase.h
@@ -25,7 +26,7 @@ shared_LIBRARIES = ulut
 endif
 
 ulut_SOURCES = ul_dbufbase.c ul_dbufmore.c ul_gsa.c ul_gsacust.c \
-              ul_gavlprim.c ul_hptree.c \
+              ul_gavlprim.c ul_hashtabprim.c ul_hptree.c \
               ul_htimer.c ul_htimbase.c ul_htimroot.c \
               ul_htimdefault.c ul_dbufflog.c ul_logbase.c \
               ul_cbuff.c
@@ -38,12 +39,13 @@ endif
 lib_LOADLIBES = ulut
 
 ifeq ($(CONFIG_OC_ULUT_TESTS),y)
-utils_PROGRAMS = ul_gavlchk ul_gsachk ul_htimchk
+utils_PROGRAMS = ul_gavlchk ul_gsachk ul_htimchk ul_hashtabchk
 endif
 
 ul_gavlchk_SOURCES = ul_gavlchk.c
 ul_gsachk_SOURCES = ul_gsachk.c
 ul_htimchk_SOURCES = ul_htimchk.c
+ul_hashtabchk_SOURCES = ul_hashtabchk.c
 
 endif
 
diff --git a/ulut/ul_hashtab.h b/ulut/ul_hashtab.h
new file mode 100644 (file)
index 0000000..7121fc6
--- /dev/null
@@ -0,0 +1,155 @@
+/*******************************************************************
+  uLan Utilities Library - C library of basic reusable constructions
+
+  ul_hashtab.h - hash table declarations
+
+  (C) Copyright 2009 by Pavel Pisa - Originator
+
+  The uLan utilities library can be used, copied and modified under
+  next licenses
+    - GPL - GNU General Public License
+    - LGPL - GNU Lesser General Public License
+    - MPL - Mozilla Public License
+    - and other licenses added by project originators
+  Code can be modified and re-distributed under any combination
+  of the above listed licenses. If contributor does not agree with
+  some of the licenses, he/she can delete appropriate line.
+  Warning, if you delete all lines, you are not allowed to
+  distribute source code and/or binaries utilizing code.
+  
+  See files COPYING and README for details.
+
+ *******************************************************************/
+
+#ifndef _UL_HASHTAB_H
+#define _UL_HASHTAB_H
+
+#include "ul_utdefs.h"
+#include "ul_itbase.h"
+#include "ul_gavl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned int ul_hashtab_hashval_t;
+
+/**
+ * struct ul_hastab_node - Structure Representing Node of Generic AVL Tree
+ * @treenode:  place to store GAVL node information
+ */
+typedef struct ul_hashtab_node {
+  gavl_node_t treenode;
+} ul_hashtab_node_t;
+
+/**
+ * struct ul_hashtab_node_hashcache - Structure Representing Node of Generic AVL Tree
+ * @treenode:  place to store GAVL node information
+ * @hashval:   place to store computed hash value
+ */
+typedef struct ul_hashtab_node_hashval {
+  gavl_node_t treenode;
+  ul_hashtab_hashval_t hashval;
+} ul_hashtab_node_hashval_t;
+
+typedef struct ul_hashtab_treeroot {
+  gavl_cust_root_field_t treeroot;
+} ul_hashtab_treeroot_t;
+
+/**
+ * struct ul_hashtab_cust_table_field - Structure Representing Hash Table
+ * @count:     number of inserted items
+ * @hashmask:  mask of bits used to index into actual allocated size
+ * @treeroots: internal storage for hash resolution
+ */
+
+typedef struct ul_hashtab_cust_table_field {
+  union {
+    ul_hashtab_treeroot_t *treetable;
+    ul_hashtab_treeroot_t treesingle;
+  } treeroots;
+  long count;
+  ul_hashtab_hashval_t hashmask;
+} ul_hashtab_cust_table_field_t;
+
+typedef int (ul_hashtab_resize_insert_fnc_t)(ul_hashtab_cust_table_field_t *table_field, gavl_node_t *treenode) UL_ATTR_REENTRANT;
+
+void ul_hashtab_init_table_field_primitive(ul_hashtab_cust_table_field_t *table_field);
+int ul_hashtab_delete_all_primitive(ul_hashtab_cust_table_field_t *table_field);
+int ul_hashtab_resize_primitive(ul_hashtab_cust_table_field_t *table_field,
+               ul_hashtab_hashval_t newsize, ul_hashtab_resize_insert_fnc_t *ins_fnc);
+gavl_node_t *ul_hashtab_next_it_primitive(const ul_hashtab_cust_table_field_t *table_field,
+       ul_hashtab_treeroot_t **pptreeroot, gavl_node_t *treenode);
+
+/* Declaration of new custom hash table with internal node */
+#define UL_HASTAB_CUST_NODE_INT_DEC_SCOPE(cust_scope, cust_prefix, cust_table_t, cust_item_t, cust_key_t,\
+               cust_table_field, cust_item_node, cust_item_key, cust_cmp_fnc) \
+\
+typedef struct {\
+  cust_table_t *container; \
+  ul_hashtab_treeroot_t *ptreeroot; \
+  cust_item_t *item; \
+} cust_prefix##_it_t;\
+\
+cust_scope int cust_prefix##_search_node(const cust_table_t *table, cust_key_t const *key, typeof(((cust_item_t*)0)->cust_item_node) **nodep);\
+cust_scope cust_item_t *cust_prefix##_find(const cust_table_t *table, cust_key_t const *key);\
+cust_scope int cust_prefix##_insert(cust_table_t *table, cust_item_t *item);\
+cust_scope int cust_prefix##_delete_node(cust_table_t *table, gavl_node_t *node);\
+cust_scope cust_item_t *cust_prefix##_delete_key(cust_table_t *table, cust_key_t const *key);\
+cust_scope int cust_prefix##_delete(cust_table_t *table, cust_item_t *item);\
+cust_scope int cust_prefix##_resize_table(cust_table_t *table, ul_hashtab_hashval_t newsize);\
+cust_scope void cust_prefix##_next_it(cust_prefix##_it_t *it);\
+cust_scope int cust_prefix##_find_it(cust_table_t *container, cust_key_t const *key, cust_prefix##_it_t *it);\
+cust_scope void cust_prefix##_delete_it(cust_prefix##_it_t *it);\
+\
+static inline \
+void cust_prefix##_init_table_field(cust_table_t *table)\
+{\
+  return ul_hashtab_init_table_field_primitive(&table->cust_table_field);\
+} \
+\
+static inline \
+int cust_prefix##_delete_all(cust_table_t *table)\
+{\
+  return ul_hashtab_delete_all_primitive(&table->cust_table_field);\
+} \
+\
+static inline \
+cust_item_t *cust_prefix##_it2item(const cust_prefix##_it_t *it)\
+{\
+  return it->item;\
+} \
+\
+static inline int \
+cust_prefix##_is_end_it(cust_prefix##_it_t *it)\
+{\
+  return !it->item;\
+} \
+\
+static inline void \
+cust_prefix##_first_it(cust_table_t *container, cust_prefix##_it_t *it)\
+{\
+  it->container=container;\
+  it->item=NULL;\
+  cust_prefix##_next_it(it);\
+} \
+\
+void cust_prefix##_next_it(cust_prefix##_it_t *it) \
+{ \
+  gavl_node_t *treenode; \
+  treenode=ul_hashtab_next_it_primitive(\
+    &it->container->cust_table_field, &it->ptreeroot, \
+    it->item!=NULL?&it->item->cust_item_node.treenode: NULL); \
+  it->item=treenode!=NULL?UL_CONTAINEROF(treenode, cust_item_t, cust_item_node.treenode):NULL;\
+}
+
+#define UL_HASTAB_CUST_NODE_INT_DEC(cust_prefix, cust_table_t, cust_item_t, cust_key_t,\
+               cust_table_field, cust_item_node, cust_item_key, cust_cmp_fnc) \
+       UL_HASTAB_CUST_NODE_INT_DEC_SCOPE(extern, cust_prefix, cust_table_t, cust_item_t, cust_key_t,\
+               cust_table_field, cust_item_node, cust_item_key, cust_cmp_fnc)
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /* _UL_HASHTAB_H */
diff --git a/ulut/ul_hashtabchk.c b/ulut/ul_hashtabchk.c
new file mode 100644 (file)
index 0000000..7d5ab08
--- /dev/null
@@ -0,0 +1,240 @@
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifndef SDCC
+#include <sys/time.h>
+#endif
+
+#include "ul_utmalloc.h"
+#include "ul_hashtab.h"
+#include "ul_hashtabcust.h"
+
+typedef int ul_randser_int_t;
+
+#define UL_HASHTAB_WITH_HASHVAL
+
+typedef struct cust3_item {
+  int my_val;
+ #ifndef UL_HASHTAB_WITH_HASHVAL
+  ul_hashtab_node_t my_node;
+ #else /*UL_HASHTAB_WITH_HASHCACHE*/
+  ul_hashtab_node_hashval_t my_node;
+ #endif /*UL_HASHTAB_WITH_HASHCACHE*/
+  int more_data;
+} cust3_item_t;
+
+typedef struct cust3_table {
+  ul_hashtab_cust_table_field_t my_table;
+  int my_info;
+  int my_first_val;
+  int my_last_val;
+} cust3_table_t;
+
+typedef int cust3_key_t;
+
+UL_HASTAB_CUST_NODE_INT_DEC(cust3, cust3_table_t, cust3_item_t, cust3_key_t,
+       my_table, my_node, my_val, cust3_cmp_fnc)
+
+inline int
+cust3_cmp_fnc(const cust3_key_t *a, const cust3_key_t *b)
+{
+  if (*a>*b) return 1;
+  if (*a<*b) return -1;
+  return 0;
+}
+
+inline ul_hashtab_hashval_t
+cust3_hash_fnc(const cust3_key_t *a)
+{
+  return *a;
+}
+
+inline ul_hashtab_hashval_t
+cust3_hash_get_fnc(const cust3_item_t *item)
+{
+ #ifdef UL_HASHTAB_WITH_HASHVAL
+  return item->my_node.hashval;
+ #else /*UL_HASHTAB_WITH_HASHCACHE*/
+  return cust3_hash_fnc(&item->my_val);
+ #endif /*UL_HASHTAB_WITH_HASHCACHE*/
+}
+
+inline void
+cust_hash_prep_fnc(cust3_item_t *item)
+{
+ #ifdef UL_HASHTAB_WITH_HASHVAL
+  item->my_node.hashval=cust3_hash_fnc(&item->my_val);
+ #endif /*UL_HASHTAB_WITH_HASHCACHE*/
+}
+
+UL_HASTAB_CUST_NODE_INT_IMP(cust3, cust3_table_t, cust3_item_t, cust3_key_t,
+       my_table, my_node, my_val, cust3_cmp_fnc, cust3_hash_fnc,
+       cust3_hash_get_fnc, cust_hash_prep_fnc, 0, 0)
+
+
+cust3_table_t cust3_table;
+
+ul_randser_int_t *ul_randser_generate(ul_randser_int_t len)
+{
+  ul_randser_int_t *ser;
+  ul_randser_int_t i;
+
+  ser=malloc(sizeof(*ser)*len);
+  if(ser==NULL)
+    return NULL;
+
+  for(i=0; i<len; i++) {
+    ser[i]=i;
+  }
+
+  for(i=len; i--; ) {
+    ul_randser_int_t t, k;
+    k=rand();
+    k=(unsigned long long)k*i/RAND_MAX;
+    t=ser[k];
+    ser[k]=ser[i];
+    ser[i]=t;
+  }
+
+  return ser;
+}
+
+void timing_test_print(struct timeval *start, struct timeval *stop, char *s)
+{
+  long sec, usec;
+  sec=stop->tv_sec-start->tv_sec;
+  usec=stop->tv_usec-start->tv_usec;
+  if(usec>=1000000) {
+    usec-=1000000;
+    sec++;
+  }
+  if(usec<0) {
+    usec+=1000000;
+    sec--;
+  }
+  printf("%s :\t%4ld.%06ld\n",s,sec,usec);
+}
+
+int main(int argc, char *argv[])
+{
+  cust3_table_t *table=&cust3_table;
+  cust3_item_t *item;
+  cust3_key_t k;
+  cust3_it_t it;
+  int count=100000;
+  int tablepow=12;
+  cust3_item_t **item_arr;
+  struct timeval time_start, time_stop;
+  int i, j;
+  int res;
+  ul_randser_int_t *ser1, *ser2;
+
+  cust3_init_table_field(table);
+
+  if(argc>=2) {
+    count=atol(argv[1]);
+  }
+  if(argc>=3) {
+    tablepow=atol(argv[2]);
+  }
+
+  cust3_resize_table(table, 1<<tablepow);
+
+  ser1=ul_randser_generate(count);
+  if(ser1==NULL)
+    return 1;
+
+  ser2=ul_randser_generate(count);
+  if(ser2==NULL)
+    return 1;
+
+  item_arr=malloc(sizeof(*item_arr)*count);
+  if(!item_arr)
+    return 1;
+
+  for(i=0; i<count; i++) {
+    item=malloc(sizeof(*item));
+    item->my_val=ser1[i];
+    item_arr[i]=item;
+  }
+
+  gettimeofday(&time_start,NULL);
+  for(i=0; i<count; i++) {
+    res=cust3_insert(table, item_arr[i]);
+    if(res<=0) {
+      printf("cust3_insert %d returned %d\n", i, res);
+    }
+  }
+  gettimeofday(&time_stop,NULL);
+  timing_test_print(&time_start,&time_stop,"HASHTAB random insert");
+
+  gettimeofday(&time_start,NULL);
+  for(j=0; j<10; j++) {
+    for(i=0; i<count; i++) {
+      k=ser2[i];
+      item=cust3_find(table, &k);
+      if(item==NULL) {
+        printf("cust3_find %d failed to found item\n", k);
+      }
+    }
+  }
+  gettimeofday(&time_stop,NULL);
+  timing_test_print(&time_start,&time_stop,"HASHTAB random find 10x");
+
+ #if 0
+  for(k=10; (k<count) && (k<20); k++) {
+    item=cust3_find(table, &k);
+    if(item==NULL) {
+      printf("cust3_find %d failed to found item in loop 2\n", k);
+      continue;
+    }
+    if(cust3_delete(table, item)<0)
+      printf("cust3_delete failed to found item %d\n", item->my_val);
+    else
+      free(item);
+  }
+
+  for(k=20; k<count; k++) {
+    item=cust3_delete_key(table, &k);
+    if(item==NULL)
+      printf("cust3_delete_key failed to found key %d\n", k);
+    else
+      free(item);
+  }
+ #endif
+
+  gettimeofday(&time_start,NULL);
+  for(j=0; j<10; j++) {
+    i=0;
+    ul_for_each_it(cust3, table, it){
+      item=cust3_it2item(&it);
+      if(item) {
+        i++;
+      } else {
+        printf("ul_for_each_it error\n");
+      }
+    }
+    if(i!=table->my_table.count)
+      printf("ul_for_each_it skipped some items\n");
+  }
+  gettimeofday(&time_stop,NULL);
+  timing_test_print(&time_start,&time_stop,"HASHTAB for each by iterator 10x");
+
+  gettimeofday(&time_start,NULL);
+  for(cust3_first_it(table,&it); !cust3_is_end_it(&it); ) {
+    item=cust3_it2item(&it);
+    cust3_delete_it(&it);
+    free(item);
+  }
+  gettimeofday(&time_stop,NULL);
+  timing_test_print(&time_start,&time_stop,"HASHTAB delete rest by iterator");
+
+  cust3_delete_all(table);
+
+  free(ser1);
+  free(ser2);
+  free(item_arr);
+
+  return 0;
+}
\ No newline at end of file
diff --git a/ulut/ul_hashtabcust.h b/ulut/ul_hashtabcust.h
new file mode 100644 (file)
index 0000000..e5353ca
--- /dev/null
@@ -0,0 +1,149 @@
+/*******************************************************************
+  uLan Utilities Library - C library of basic reusable constructions
+
+  ul_hastabcust.h      - custom hash table implementation
+
+  (C) Copyright 2009 by Pavel Pisa - Originator
+
+  The uLan utilities library can be used, copied and modified under
+  next licenses
+    - GPL - GNU General Public License
+    - LGPL - GNU Lesser General Public License
+    - MPL - Mozilla Public License
+    - and other licenses added by project originators
+  Code can be modified and re-distributed under any combination
+  of the above listed licenses. If contributor does not agree with
+  some of the licenses, he/she can delete appropriate line.
+  Warning, if you delete all lines, you are not allowed to
+  distribute source code and/or binaries utilizing code.
+  
+  See files COPYING and README for details.
+
+ *******************************************************************/
+
+#ifndef _UL_HASHTABCUST_H
+#define _UL_HASHTABCUST_H
+
+#include "ul_utdefs.h"
+#include "ul_hashtab.h"
+#include "ul_gavlcust.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UL_HASTAB_CUST_NODE_INT_IMP(cust_prefix, cust_table_t, cust_item_t, cust_key_t,\
+               cust_table_field, cust_item_node, cust_item_key, cust_cmp_fnc, cust_hash_fnc, \
+               cust_hash_get_fnc, cust_hash_prep_fnc, cust_expand_ratio, cust_shrink_ratio) \
+GAVL_CUST_NODE_INT_DEC_SCOPE(static, cust_prefix##_privtree, ul_hashtab_treeroot_t, cust_item_t, cust_key_t,\
+       treeroot, cust_item_node.treenode, cust_item_key, cust_cmp_fnc) \
+GAVL_CUST_NODE_INT_IMP(cust_prefix##_privtree, ul_hashtab_treeroot_t, cust_item_t, cust_key_t,\
+       treeroot, cust_item_node.treenode, cust_item_key, cust_cmp_fnc) \
+\
+static inline \
+ul_hashtab_treeroot_t *cust_prefix##_privtree_tree4item(cust_table_t *table, const cust_item_t *item)\
+{\
+  return !table->cust_table_field.hashmask? &(table->cust_table_field.treeroots.treesingle):\
+    &(table->cust_table_field.treeroots.treetable[cust_hash_get_fnc(item)&table->cust_table_field.hashmask]);\
+} \
+\
+static inline \
+const ul_hashtab_treeroot_t *cust_prefix##_privtree_tree4key(const cust_table_t *table, cust_key_t const *key)\
+{\
+  return !table->cust_table_field.hashmask? &(table->cust_table_field.treeroots.treesingle):\
+    &(table->cust_table_field.treeroots.treetable[cust_hash_fnc(key)&table->cust_table_field.hashmask]);\
+} \
+\
+static \
+int cust_prefix##_privinternal_insert(cust_table_t *table, cust_item_t *item)\
+{\
+  return cust_prefix##_privtree_insert(cust_prefix##_privtree_tree4item(table, item), item);\
+} \
+\
+static \
+int cust_prefix##_privresize_insert(ul_hashtab_cust_table_field_t *table_field, gavl_node_t *treenode) UL_ATTR_REENTRANT\
+{\
+  return cust_prefix##_privinternal_insert(UL_CONTAINEROF(table_field, cust_table_t, cust_table_field),\
+                                           cust_prefix##_privtree_node2item(NULL,treenode));\
+} \
+\
+int cust_prefix##_resize_table(cust_table_t *table, ul_hashtab_hashval_t newsize)\
+{\
+  return ul_hashtab_resize_primitive(&table->cust_table_field, newsize, cust_prefix##_privresize_insert);\
+} \
+\
+int cust_prefix##_insert(cust_table_t *table, cust_item_t *item)\
+{\
+  int res;\
+  if(cust_expand_ratio<=0?0:(table->cust_table_field.count/cust_expand_ratio>table->cust_table_field.hashmask)) \
+      cust_prefix##_resize_table(table, (table->cust_table_field.hashmask+1)<<1);\
+  cust_hash_prep_fnc(item);\
+  res=cust_prefix##_privinternal_insert(table, item);\
+  if(res>0) \
+    table->cust_table_field.count++; \
+  return res; \
+} \
+\
+int cust_prefix##_delete(cust_table_t *table, cust_item_t *item)\
+{\
+  int res;\
+  res=cust_prefix##_privtree_delete(cust_prefix##_privtree_tree4item(table, item), item);\
+  if(res>0) { \
+    table->cust_table_field.count--; \
+    if(cust_shrink_ratio<=0?0:(table->cust_table_field.count/cust_shrink_ratio<table->cust_table_field.hashmask)) \
+      cust_prefix##_resize_table(table, (table->cust_table_field.hashmask>>1)+1);\
+  }\
+  return res; \
+} \
+\
+cust_item_t *cust_prefix##_delete_key(cust_table_t *table, cust_key_t const *key) \
+{\
+  gavl_node_t *node; \
+  const ul_hashtab_treeroot_t *treeroot; \
+  treeroot=cust_prefix##_privtree_tree4key(table, key); \
+  if(cust_prefix##_privtree_search_node(treeroot, key, &node)) \
+    return NULL; \
+  cust_prefix##_privtree_delete_node((ul_hashtab_treeroot_t *)treeroot, node); \
+  return cust_prefix##_privtree_node2item(NULL,node); \
+} \
+\
+int cust_prefix##_search_node(const cust_table_t *table, cust_key_t const *key, typeof(((cust_item_t*)0)->cust_item_node) **nodep) \
+{\
+  gavl_node_t *node;\
+  if(cust_prefix##_privtree_search_node(cust_prefix##_privtree_tree4key(table, key), key, &node)) { \
+    *nodep=NULL; \
+    return -1; \
+  } \
+  *nodep=&(UL_CONTAINEROF(node, cust_item_t, cust_item_node.treenode)->cust_item_node); \
+  return 0; \
+} \
+\
+cust_item_t *cust_prefix##_find(const cust_table_t *table, cust_key_t const *key) \
+{\
+  return cust_prefix##_privtree_find(cust_prefix##_privtree_tree4key(table, key), key); \
+} \
+\
+int cust_prefix##_find_it(cust_table_t *container, cust_key_t const *key, cust_prefix##_it_t *it) \
+{\
+  it->container=container; \
+  it->ptreeroot=(ul_hashtab_treeroot_t*)cust_prefix##_privtree_tree4key(it->container, key); \
+  it->item=cust_prefix##_privtree_find(it->ptreeroot, key); \
+  return it->item!=NULL?1:0; \
+}\
+\
+void cust_prefix##_delete_it(cust_prefix##_it_t *it)\
+{\
+  cust_item_t *item;\
+  ul_hashtab_treeroot_t *treeroot; \
+  if(!(item=it->item)) return;\
+  treeroot=it->ptreeroot; \
+  cust_prefix##_next_it(it);\
+  if(cust_prefix##_privtree_delete(treeroot,item)>=0)\
+    it->container->cust_table_field.count--; \
+}
+
+#ifdef __cplusplus
+} /* extern "C"*/
+#endif
+
+#endif /* _UL_HASHTABCUST_H */
diff --git a/ulut/ul_hashtabprim.c b/ulut/ul_hashtabprim.c
new file mode 100644 (file)
index 0000000..37f6eb4
--- /dev/null
@@ -0,0 +1,125 @@
+/*******************************************************************
+  uLan Utilities Library - C library of basic reusable constructions
+
+  ul_hashtabprim.c     - primitives to support hash tables
+
+  (C) Copyright 2009 by Pavel Pisa - Originator
+
+  The uLan utilities library can be used, copied and modified under
+  next licenses
+    - GPL - GNU General Public License
+    - LGPL - GNU Lesser General Public License
+    - MPL - Mozilla Public License
+    - and other licenses added by project originators
+  Code can be modified and re-distributed under any combination
+  of the above listed licenses. If contributor does not agree with
+  some of the licenses, he/she can delete appropriate line.
+  Warning, if you delete all lines, you are not allowed to
+  distribute source code and/or binaries utilizing code.
+  
+  See files COPYING and README for details.
+
+ *******************************************************************/
+
+#include <string.h>
+#include "ul_utmalloc.h"
+#include "ul_hashtab.h"
+
+void ul_hashtab_init_table_field_primitive(ul_hashtab_cust_table_field_t *table_field)
+{
+  table_field->hashmask=0;
+  table_field->count=0;
+  table_field->treeroots.treesingle.treeroot=NULL;
+}
+
+int ul_hashtab_delete_all_primitive(ul_hashtab_cust_table_field_t *table_field)
+{
+  if(table_field->hashmask)
+    free(table_field->treeroots.treetable);
+  table_field->hashmask=0;
+  table_field->count=0;
+  table_field->treeroots.treesingle.treeroot=NULL;
+  return 0;
+}
+
+int ul_hashtab_resize_primitive(ul_hashtab_cust_table_field_t *table_field,
+               ul_hashtab_hashval_t newsize, ul_hashtab_resize_insert_fnc_t *ins_fnc)
+{
+  ul_hashtab_hashval_t oldsize=table_field->hashmask+1;
+  ul_hashtab_treeroot_t oldsingle;
+  ul_hashtab_treeroot_t *pt;
+  ul_hashtab_treeroot_t *oldtable;
+  gavl_node_t *treenode;
+  int res;
+
+  if(newsize<=0)
+    newsize=1;
+
+  if(oldsize>1) {
+    oldtable=table_field->treeroots.treetable;
+  } else {
+    oldsingle.treeroot=table_field->treeroots.treesingle.treeroot;
+    oldtable=NULL;
+  }
+
+  if(newsize>1) {
+    pt=malloc(sizeof(*pt)*newsize);
+    if(pt==NULL)
+      return -1;
+    memset(pt,0,sizeof(*pt)*newsize);
+    table_field->treeroots.treetable=pt;
+  } else {
+    table_field->treeroots.treesingle.treeroot=NULL;
+  }
+  table_field->hashmask=newsize-1;
+
+  pt = oldtable!=NULL? oldtable: &oldsingle;
+
+  while(oldsize--) {
+    while(pt->treeroot!=NULL) {
+      treenode=gavl_cut_first_primitive(&pt->treeroot);
+      res=ins_fnc(table_field, treenode);
+    }
+    pt++;
+  }
+
+  if(oldtable)
+    free(oldtable);
+
+  return 0;
+}
+
+gavl_node_t *ul_hashtab_next_it_primitive(const ul_hashtab_cust_table_field_t *table_field,
+       ul_hashtab_treeroot_t **pptreeroot, gavl_node_t *treenode)
+{
+  if(treenode!=NULL) {
+    treenode=gavl_next_node(treenode);
+    if((treenode!=NULL) || !table_field->hashmask)
+      return treenode;
+    if(table_field->treeroots.treetable+table_field->hashmask==*pptreeroot)
+      return treenode;
+    (*pptreeroot)++;
+  } else {
+    if(!table_field->hashmask) {
+      const ul_hashtab_treeroot_t *treeroot=&table_field->treeroots.treesingle;
+      *pptreeroot=(ul_hashtab_treeroot_t *)treeroot;
+    } else {
+      *pptreeroot=table_field->treeroots.treetable;
+    }
+  }
+  do {
+    if(*pptreeroot) {
+      treenode=(*pptreeroot)->treeroot;
+      if(treenode)
+        while(treenode->left!=NULL)
+          treenode=treenode->left;
+      if(treenode!=NULL)
+        return treenode;
+    }
+    if(!table_field->hashmask)
+      return treenode;
+    if(table_field->treeroots.treetable+table_field->hashmask==*pptreeroot)
+      return treenode;
+    (*pptreeroot)++;
+  } while (1);
+}