2of1
half a nibble of another

Home
Projects
About
Jul

11

Simple C hashtable code

Filed Under (C, Coding, Open source) by 2of1 on 11-07-2011

Here’s some code for a simple C hashtable.

The hashtable uses char * for keys, allows any type of data to be stored, allows for an arbitrary size and uses linked-lists for collision handling.

hash.h
(Download here)

/* simple hashtable
 * David Kaplan <david[at]2of1.org>, 2011
 *
 * mem = (16 + 8 * size + 24 * entries) bytes [64-bit]
 * mem = (8 + 4 * size + 12 * entries) bytes [32-bit]
 *
 * some sizes for reference [64-bit]
 * 2^8  = 16K [probably too small - depending on use]
 * 2^16 = 512K [even bigger would be better]
 * 2^24 = 128MB [probably a bit too much]
 * 2^32 = 32GB [whooooa! watch that heap space!]
 *
 * the hashtable uses basic linked-lists for handling collisions
 */
 
#define HT_MAX_KEYLEN 50
 
struct ht_node {
  void *val;
  char *key;
  struct ht_node *nxt;
};
 
typedef struct ht {
  struct ht_node **tbl;
  int size;
} HT;
 
HT *ht_create(int size);                    /* allocate hashtable mem */
void ht_destroy(HT *ht);                    /* free hashtable mem */
void *ht_get(HT *ht, char *key);            /* retrieve entry */
void ht_put(HT *ht, char *key, void *val);  /* store entry */
void ht_remove(HT *ht, char *key);          /* remove entry */

hash.c
(Download here)

#include <stdio.h>
#include <stdint.h>
#include <malloc.h>
#include <string.h>
 
#include "hash.h"
 
unsigned long _hash(char *key)
{
  /* djb2 */
  unsigned long hash = 5381;
  int c;
 
  while (c = *key++)
    hash = ((hash << 5) + hash) + c;
 
  return hash;
}
 
HT *ht_create(int size)
{
  HT *ht = malloc(sizeof(HT));
 
  ht->size = size;
 
  ht->tbl = calloc(1, size * sizeof(struct ht_node *));
 
  return ht;
}
 
void ht_destroy(HT *ht)
{
  if (!ht) return;
 
  int i;
  for (i = 0; i < ht->size; i++) {
    struct ht_node *n = ht->tbl[i];
    while (n) {
      struct ht_node *n_old = n;
 
      n = n->nxt;
 
      free(n_old->key);
      n_old->key = NULL;
      free(n_old);
      n_old = NULL;
    }
  }
 
  free(ht->tbl);
  free(ht);
 
  ht = NULL;
}
 
void *ht_get(HT *ht, char *key)
{
  if (!ht) return NULL;
 
  unsigned long idx = _hash(key) % ht->size;
 
  struct ht_node *n = ht->tbl[idx];
  while (n) {
    if (strncmp(key, n->key, HT_MAX_KEYLEN) == 0)
      return n->val;
 
    n = n->nxt;
  }
 
  return NULL;
}
 
void ht_put(HT *ht, char *key, void *val)
{
  if (!ht) return;
 
  unsigned long idx = _hash(key) % ht->size;
 
  struct ht_node *n_new = calloc(1, sizeof(struct ht_node));
  n_new->val = val;
  n_new->key = calloc(1, strnlen(key, HT_MAX_KEYLEN) + 1);
  strcpy(n_new->key, key);
 
  n_new->nxt = ht->tbl[idx];
  ht->tbl[idx] = n_new;
}
 
void ht_remove(HT *ht, char *key)
{
  if (!ht) return;
 
  unsigned long idx = _hash(key) % ht->size;
 
  struct ht_node *p = NULL, *n = ht->tbl[idx];
  while (n) {
    if (strncmp(key, n->key, HT_MAX_KEYLEN) == 0) {
      if (p)
        p->nxt = n->nxt;
 
      free (n->key);
      n->key = NULL;
 
      if (ht->tbl[idx] == n)
        ht->tbl[idx] = NULL;
 
      free (n);
      n = NULL;
 
      break;
    }
 
    p = n;
    n = n->nxt;
  }
}
(3) Comments
Read More

Comments:

3 Responses to “Simple C hashtable code”

  1. 2of1 on 11 Jul 2011 at 1:09 pm

    Bug reports welcome!

  2. Yoram on 12 Jul 2011 at 6:44 am

    This impelementation exposes how using bare char * causes performance penalty because of runtime length calculations. since on many cases the length of the key is known before putting it, somethime even at compile time, API the accepts pointer and size can be faster.
    Also, using tables sizes which are powers of 2 (8, 1024, etc..) let you avoid modules be replacing hash % ht->size with hash & (ht->size -1).

  3. 2of1 on 12 Jul 2011 at 10:56 am

    Yup. I agree.
    Performance in this particular application isn’t such an issue but I agree that it’s a good thing to consider – especially since one of the points of a hashtable in the first place is to increase performance.
    When I have some time maybe I’ll update the above code to include your suggestions.

Leave a Reply

  • Recent Posts

    • ARM long branch
    • Mini-Namco #3: (Almost) Finished
    • Mini-Namco #2: Unit construction
    • Mini-Namco #1: Design
    • Simple C hashtable code
  • Archives

    • January 2012
    • September 2011
    • August 2011
    • July 2011
    • May 2011
    • March 2011
    • February 2011
    • January 2011
    • November 2010
    • October 2010
    • September 2010
    • August 2010
    • July 2010
    • June 2010
  • GitHub

    • code
    • d2d1headers
    • locateme
    • findjerusalem
    • seg7
    • userspace-krb
    • libgmail
    • preloader
    • linhook
  • qrcode

  • Site Search

  • Categories

    • Apps (7)
      • Preloader (1)
      • Symbian S60 (1)
      • VLC (4)
      • Wordpress (1)
    • Coding (28)
      • Assembly (1)
        • ARM (1)
      • C (12)
      • Compilers (5)
      • Direct2D API (4)
      • Linux kernel (2)
      • Networking (4)
      • Python (1)
      • Sqlite (1)
      • Version control (5)
        • Git (5)
    • Hacking (4)
      • Code injection (1)
      • Reverse engineering (3)
    • Hardware (4)
      • Arduino (1)
      • PCBs (3)
    • Linux (21)
      • Bash (1)
      • Tips & tricks (13)
      • Virtualization (1)
      • VNC (2)
      • Xmonad (1)
    • Open source (30)
    • Other stuffs (3)
    • Social (3)
      • DC9723 (2)
  • OctoFinderProgramming Blogs - Blog Catalog Blog Directory

    Locations of visitors to this page

© 2of1.