Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tj committed Jun 17, 2012
0 parents commit 97bda25
Show file tree
Hide file tree
Showing 5 changed files with 291 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
deps
test
9 changes: 9 additions & 0 deletions Makefile
@@ -0,0 +1,9 @@

test: hash.c
@$(CC) -std=c99 -DTEST_HASH $^ -o $@
@./test

clean:
rm -f test

.PHONY: test clean
179 changes: 179 additions & 0 deletions hash.c
@@ -0,0 +1,179 @@

//
// hash.c
//
// Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
//

#include "hash.h"

/*
* Set hash `key` to `val`.
*/

inline void
hash_set(hash_t *self, char *key, void *val) {
int ret;
khiter_t k = kh_put(ptr, self, key, &ret);
kh_value(self, k) = val;
}

/*
* Get hash `key`, or NULL.
*/

inline void *
hash_get(hash_t *self, char *key) {
khiter_t k = kh_get(ptr, self, key);
return k == kh_end(self) ? NULL : kh_value(self, k);
}

/*
* Check if hash `key` exists.
*/

inline int
hash_has(hash_t *self, char *key) {
khiter_t k = kh_get(ptr, self, key);
return kh_exist(self, k);
}

/*
* Remove hash `key`.
*/

void
hash_remove(hash_t *self, char *key) {
khiter_t k = kh_get(ptr, self, key);
kh_del(ptr, self, k);
}

// tests

#ifdef TEST_HASH

#include <stdio.h>
#include <assert.h>
#include <string.h>

void
test_hash_set() {
hash_t *hash = hash_new();
assert(0 == hash_size(hash));

hash_set(hash, "name", "tobi");
hash_set(hash, "species", "ferret");
assert(2 == hash_size(hash));

assert(0 == strcmp("tobi", hash_get(hash, "name")));
assert(0 == strcmp("ferret", hash_get(hash, "species")));
}

void
test_hash_get() {
hash_t *hash = hash_new();
hash_set(hash, "foo", "bar");
assert(0 == strcmp("bar", hash_get(hash, "foo")));
assert(NULL == hash_get(hash, "bar"));
}

void
test_hash_has() {
hash_t *hash = hash_new();
hash_set(hash, "foo", "bar");
assert(1 == hash_has(hash, "foo"));
assert(0 == hash_has(hash, "bar"));
}

void
test_hash_size() {
hash_t *hash = hash_new();
assert(0 == hash_size(hash));
hash_set(hash, "foo", "bar");
assert(1 == hash_size(hash));
hash_set(hash, "bar", "baz");
assert(2 == hash_size(hash));
}

void
test_hash_remove() {
hash_t *hash = hash_new();
hash_set(hash, "foo", "bar");
assert(1 == hash_has(hash, "foo"));
assert(0 == hash_has(hash, "bar"));
hash_remove(hash, "foo");
hash_remove(hash, "bar");
assert(0 == hash_has(hash, "foo"));
}

void
test_hash_each() {
hash_t *hash = hash_new();
hash_set(hash, "name", "tj");
hash_set(hash, "age", "25");

const char *keys[2];
void *vals[2];
int n = 0;

hash_each(hash, {
keys[n] = key;
vals[n] = val;
n++;
});

assert(0 == strcmp("age", keys[0]));
assert(0 == strcmp("name", keys[1]));
assert(0 == strcmp("25", vals[0]));
assert(0 == strcmp("tj", vals[1]));
}

void
test_hash_each_key() {
hash_t *hash = hash_new();
hash_set(hash, "name", "tj");
hash_set(hash, "age", "25");

const char *keys[2];
int n = 0;

hash_each_key(hash, {
keys[n++] = key;
});

assert(0 == strcmp("age", keys[0]));
assert(0 == strcmp("name", keys[1]));
}

void
test_hash_each_val() {
hash_t *hash = hash_new();
hash_set(hash, "name", "tj");
hash_set(hash, "age", "25");

void *vals[2];
int n = 0;

hash_each_val(hash, {
vals[n++] = val;
});

assert(0 == strcmp("25", vals[0]));
assert(0 == strcmp("tj", vals[1]));
}

int
main(){
test_hash_set();
test_hash_get();
test_hash_has();
test_hash_remove();
test_hash_size();
test_hash_each();
test_hash_each_key();
test_hash_each_val();
printf("\n \e[32m\u2713 \e[90mok\e[0m\n\n");
return 0;
}

#endif
97 changes: 97 additions & 0 deletions hash.h
@@ -0,0 +1,97 @@

//
// hash.h
//
// Copyright (c) 2012 TJ Holowaychuk <tj@vision-media.ca>
//

#ifndef HASH
#define HASH

#include "deps/khash/khash.h"

// pointer hash

KHASH_MAP_INIT_STR(ptr, void *);

/*
* Hash type.
*/

typedef khash_t(ptr) hash_t;

/*
* Allocate a new hash.
*/

#define hash_new() kh_init(ptr)

/*
* Destroy the hash.
*/

#define hash_free(self) kh_destroy(ptr, self)

/*
* Hash size.
*/

#define hash_size kh_size

/*
* Iterate hash keys and ptrs, populating
* `key` and `val`.
*/

#define hash_each(self, block) { \
const char *key; \
void *val; \
for (khiter_t k = kh_begin(self); k < kh_end(self); ++k) { \
if (!kh_exist(self, k)) continue; \
key = kh_key(self, k); \
val = kh_value(self, k); \
block; \
} \
}

/*
* Iterate hash keys, populating `key`.
*/

#define hash_each_key(self, block) { \
const char *key; \
for (khiter_t k = kh_begin(self); k < kh_end(self); ++k) { \
if (!kh_exist(self, k)) continue; \
key = kh_key(self, k); \
block; \
} \
}

/*
* Iterate hash ptrs, populating `val`.
*/

#define hash_each_val(self, block) { \
void *val; \
for (khiter_t k = kh_begin(self); k < kh_end(self); ++k) { \
if (!kh_exist(self, k)) continue; \
val = kh_value(self, k); \
block; \
} \
}

// protos

void
hash_set(hash_t *self, char *key, void *val);

void *
hash_get(hash_t *self, char *key);

int
hash_has(hash_t *self, char *key);

void
hash_remove(hash_t *self, char *key);

#endif /* HASH */
4 changes: 4 additions & 0 deletions package.conf
@@ -0,0 +1,4 @@
name: hash
version: 0.0.1
description: Hash API built on khash
dependencies: khash

0 comments on commit 97bda25

Please sign in to comment.