Logo Search packages:      
Sourcecode: ldapdns version File versions  Download package

ht.c

#include <string.h>
#include <stdlib.h>

#include "bin.h"
#include "ht.h"
#include "mem.h"

int ht_init(ht *x, unsigned tab, unsigned long (*hash)(const void *,unsigned))
{
      unsigned tmps;

      x->b = (htbucket **)mem_alloc(tmps = tab * sizeof(htbucket *));
      if (!x->b) return -1;
      memzero(x->b, tmps);

      x->ondel = 0;
      x->onwrite = 0;
      x->onfail = 0;

      x->s = tab;
      x->hash = hash;
      return 1;
}
static int ht_die_fn(ht *x, void *key, unsigned klen, void *data)
{
      if (ht_delete(x, key, klen) != 1)
            return HT_WILLFAIL;
      return HT_RESTART;
}
int ht_die(ht *x)
{
      if (ht_walk(x, ht_die_fn) == -1)
            return 1;
      return 0;
}
int ht_ondelete(ht *x, int (*fn)(void *data))
{
      x->ondel = fn;
      return 1;
}
int ht_onwrite(ht *x, void (*fn)(const void *,unsigned,const void *))
{
      x->onwrite = fn;
      return 1;
}
int ht_onfail(ht *x, int (*fn)(const void *, unsigned))
{
      x->onfail = fn;
      return 1;
}
int ht_walk(ht *x, int (*fn)(ht *x, void *key, unsigned klen, void *data))
{
      unsigned i;
      union { void *A; const void *B; } qu;
      htbucket *n;
      int ret = -1;

restart_l:
      for (i = 0; i < x->s; i++) {
            n = x->b[i];
            if (n == 0)
                  continue;
            while (n) {
                  qu.B = n->key;
                  switch (fn(x, qu.A, n->klen, n->data)) {
                  case HT_RESTART:  goto restart_l;
                  case HT_FAILNOW:  return 0;
                  case HT_SUCCESSNOW:     return 1;
                  case HT_TRIPSUCCESS:    ret = 1; break;
                  case HT_TRIPFAIL: ret = 0; break;
                  case HT_WILLSUCCESS:    if (ret != 0) ret = 1; break;
                  case HT_WILLFAIL: if (ret != 1) ret = 0; break;
                  case HT_NEXT:           break;
                  case HT_AGAIN:          continue;
                  };
                  n = (htbucket *)n->next;
            }
      }
      return ret;
}

static int ht_store_flag(ht *x, const void *key, unsigned klen,
            void *data, int flag, int i)
{
      htbucket *n;
      unsigned long hash;
      unsigned pos;
      bin_t kx;

      hash = x->hash(key, klen);
      n = x->b[pos = hash % x->s];
      while (n) {
            if (n->hash == hash && n->klen == klen &&
                  memcmp(key, n->key, klen) == 0) {
                  return 0; /* collision */
            }
            n = (htbucket *)n->next;
      }

      n = (htbucket *)mem_alloc(sizeof(htbucket));
      if (!n) return -1;

      bin_init(kx);
      bin_copy(kx, key, klen);
      n->key = caddr(kx);
      n->klen = klen;
      n->hash = x->hash(key, klen);;
      n->data = data;
      n->next = (void *)x->b[pos];
      n->free_data = flag;
      n->idata = i;

      x->b[pos] = (htbucket *)n;
      /* write to log (as necessary) */
      if (x->onwrite)
            x->onwrite(n->key, n->klen, n->data);

      return 1;
}
int ht_store(ht *x, const void *key, unsigned klen, void *data)
{
      return ht_store_flag(x, key, klen, data, 0, -1);
}
int ht_storeint(ht *x, const void *key, unsigned klen, int i)
{
      return ht_store_flag(x, key, klen, 0, 0, i);
}
int ht_storecopy(ht *x, const void *key, unsigned klen, void *data, unsigned dlen)
{
      int ret;
      void *copy;

      copy = (void *)mem_alloc(dlen);
      if (!copy) return -1;
      memcpy(copy, data, dlen);
      ret = ht_store_flag(x, key, klen, copy, 1, -1);

      if (ret != 1)
            mem_free(copy);
      return ret;
}
int ht_fetchint(ht *x, const void *key, unsigned klen)
{
      htbucket *n, *sn;
      unsigned long hash;
      int retry = 0;

      hash = x->hash(key, klen);
      sn = n = x->b[hash % x->s];
retry_fetchint_l:
      while (n) {
            if (n->hash == hash && n->klen == klen &&
                        memcmp(key, n->key, klen) == 0) {
                  return n->idata;
            }
            n = (htbucket *)n->next;
      }
      if (x->onfail && !retry) {
            if (x->onfail(key, klen) == HT_RESTART) {
                  n = sn;
                  retry = 1;
                  goto retry_fetchint_l;
            }
      }
      return -1;
}
void *ht_fetch(ht *x, const void *key, unsigned klen)
{
      htbucket *n, *sn;
      unsigned long hash;
      int retry = 0;

      hash = x->hash(key, klen);
      sn = n = x->b[hash % x->s];
retry_fetch_l:
      while (n) {
            if (n->hash == hash && n->klen == klen &&
                  memcmp(key, n->key, klen) == 0) {
                  return n->data;
            }
            n = (htbucket *)n->next;
      }
      if (x->onfail && !retry) {
            if (x->onfail(key, klen) == HT_RESTART) {
                  n = sn;
                  retry = 1;
                  goto retry_fetch_l;
            }
      }
      return (void *)0;
}
int ht_delete(ht *x, const void *key, unsigned klen)
{
      htbucket *n, *ln;
      unsigned long hash;
      unsigned pos;

      hash = x->hash(key, klen);
      n = x->b[pos = hash % x->s];
      ln = 0;
      while (n) {
            if (n->hash == hash && n->klen == klen &&
                  memcmp(key, n->key, klen) == 0) {
                  if (ln)
                        ln->next = n->next;
                  else
                        x->b[pos] = n->next;
                  mem_free(n->key);
                  if (n->free_data)
                        mem_free(n->data);
                  mem_free(n);
                  return 1;
            }
            ln = n;
            n = (htbucket *)n->next;
      }
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index