add odict

This commit is contained in:
Alfred E. Heggestad 2015-08-31 07:41:41 +00:00
parent e16054be2c
commit 9ff337301d
9 changed files with 619 additions and 0 deletions

View file

@ -30,6 +30,7 @@ MODULES += fmt tmr main mem dbg sys lock mqueue
MODULES += mod conf
MODULES += bfcp
MODULES += aes srtp
MODULES += odict
INSTALL := install
ifeq ($(DESTDIR),)

View file

@ -39,6 +39,7 @@ extern "C" {
#include "re_mod.h"
#include "re_mqueue.h"
#include "re_net.h"
#include "re_odict.h"
#include "re_rtp.h"
#include "re_sdp.h"
#include "re_uri.h"

View file

@ -29,3 +29,5 @@ uint32_t hash_joaat_str(const char *str);
uint32_t hash_joaat_str_ci(const char *str);
uint32_t hash_joaat_pl(const struct pl *pl);
uint32_t hash_joaat_pl_ci(const struct pl *pl);
uint32_t hash_fast(const char *k, size_t len);
uint32_t hash_fast_str(const char *str);

44
include/re_odict.h Normal file
View file

@ -0,0 +1,44 @@
/**
* @file re_odict.h Interface to Ordered Dictionary
*
* Copyright (C) 2010 - 2015 Creytiv.com
*/
struct odict {
struct list lst;
struct hash *ht;
};
struct odict_entry {
struct le le, he;
char *key;
union {
struct odict *odict; /* ODICT_OBJECT / OJECT_ARRAY */
char *str; /* ODICT_STRING */
int64_t integer; /* ODICT_INT */
double dbl; /* ODICT_DOUBLE */
bool boolean; /* ODICT_BOOL */
} u;
enum odict_type {
ODICT_OBJECT,
ODICT_ARRAY,
ODICT_STRING,
ODICT_INT,
ODICT_DOUBLE,
ODICT_BOOL,
ODICT_NULL,
} type;
};
int odict_alloc(struct odict **op, uint32_t hash_size);
const struct odict_entry *odict_lookup(const struct odict *o, const char *key);
size_t odict_count(const struct odict *o, bool nested);
int odict_debug(struct re_printf *pf, const struct odict *o);
int odict_entry_add(struct odict *o, const char *key,
enum odict_type type, ...);
int odict_entry_debug(struct re_printf *pf, const struct odict_entry *e);
bool odict_type_iscontainer(enum odict_type type);
bool odict_type_isreal(enum odict_type type);
const char *odict_type_name(enum odict_type type);

View file

@ -134,3 +134,236 @@ uint32_t hash_joaat_pl_ci(const struct pl *pl)
{
return pl ? hash_joaat_ci(pl->p, pl->l) : 0;
}
/*
* My best guess at if you are big-endian or little-endian. This may
* need adjustment.
*/
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
__BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(i386) || defined(__i386__) || defined(__i486__) || \
defined(__i586__) || defined(__i686__) || \
defined(vax) || defined(MIPSEL))
# define HASH_LITTLE_ENDIAN 1
# define HASH_BIG_ENDIAN 0
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
__BYTE_ORDER == __BIG_ENDIAN) || \
(defined(sparc) || defined(POWERPC) || \
defined(mc68000) || defined(sel))
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 1
#else
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 0
#endif
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
#define mix(a,b,c) { \
a -= c; a ^= rot(c, 4); c += b; \
b -= a; b ^= rot(a, 6); a += c; \
c -= b; c ^= rot(b, 8); b += a; \
a -= c; a ^= rot(c,16); c += b; \
b -= a; b ^= rot(a,19); a += c; \
c -= b; c ^= rot(b, 4); b += a; \
}
#define final(a,b,c) \
{ \
c ^= b; c -= rot(b,14); \
a ^= c; a -= rot(c,11); \
b ^= a; b -= rot(a,25); \
c ^= b; c -= rot(b,16); \
a ^= c; a -= rot(c,4); \
b ^= a; b -= rot(a,14); \
c ^= b; c -= rot(b,24); \
}
static uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
{
uint32_t a,b,c;
union { const void *ptr; size_t i; } u;
/* Set up the internal state */
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
u.ptr = key;
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
const uint32_t *k = (const uint32_t *)key;
while (length > 12) {
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 12;
k += 3;
}
#ifndef VALGRIND
switch (length) {
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
case 5 : b+=k[1]&0xff; a+=k[0]; break;
case 4 : a+=k[0]; break;
case 3 : a+=k[0]&0xffffff; break;
case 2 : a+=k[0]&0xffff; break;
case 1 : a+=k[0]&0xff; break;
case 0 : return c;
}
#else /* make valgrind happy */
const uint8_t *k8 = (const uint8_t *)k;
switch (length) {
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]; break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
case 1 : a+=k8[0]; break;
case 0 : return c;
}
#endif /* !valgrind */
}
else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
const uint16_t *k = (const uint16_t *)key;
const uint8_t *k8;
while (length > 12) {
a += k[0] + (((uint32_t)k[1])<<16);
b += k[2] + (((uint32_t)k[3])<<16);
c += k[4] + (((uint32_t)k[5])<<16);
mix(a,b,c);
length -= 12;
k += 6;
}
k8 = (const uint8_t *)k;
switch (length) {
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
break;
case 0 : return c;
}
}
else {
const uint8_t *k = (const uint8_t *)key;
while (length > 12) {
a += k[0];
a += ((uint32_t)k[1])<<8;
a += ((uint32_t)k[2])<<16;
a += ((uint32_t)k[3])<<24;
b += k[4];
b += ((uint32_t)k[5])<<8;
b += ((uint32_t)k[6])<<16;
b += ((uint32_t)k[7])<<24;
c += k[8];
c += ((uint32_t)k[9])<<8;
c += ((uint32_t)k[10])<<16;
c += ((uint32_t)k[11])<<24;
mix(a,b,c);
length -= 12;
k += 12;
}
/* all the case statements fall through */
switch (length) {
case 12: c+=((uint32_t)k[11])<<24;
case 11: c+=((uint32_t)k[10])<<16;
case 10: c+=((uint32_t)k[9])<<8;
case 9 : c+=k[8];
case 8 : b+=((uint32_t)k[7])<<24;
case 7 : b+=((uint32_t)k[6])<<16;
case 6 : b+=((uint32_t)k[5])<<8;
case 5 : b+=k[4];
case 4 : a+=((uint32_t)k[3])<<24;
case 3 : a+=((uint32_t)k[2])<<16;
case 2 : a+=((uint32_t)k[1])<<8;
case 1 : a+=k[0];
break;
case 0 : return c;
}
}
final(a,b,c);
return c;
}
/**
* Calculate hash-value using fast hash algorithm.
*
* @param k Pointer to key
* @param len Key length
*
* @return Calculated hash-value
*/
uint32_t hash_fast(const char *k, size_t len)
{
static volatile int random_seed = 0x304a0012;
if (!k)
return 0;
return hashlittle(k, len, random_seed);
}
/**
* Calculate hash-value for a NULL-terminated string
*
* @param str String
*
* @return Calculated hash-value
*/
uint32_t hash_fast_str(const char *str)
{
return hash_fast(str, str_len(str));
}

146
src/odict/entry.c Normal file
View file

@ -0,0 +1,146 @@
/**
* @file odict/entry.c Ordered Dictionary -- entry
*
* Copyright (C) 2010 - 2015 Creytiv.com
*/
#include "re_types.h"
#include "re_fmt.h"
#include "re_mem.h"
#include "re_list.h"
#include "re_hash.h"
#include "re_odict.h"
static void destructor(void *arg)
{
struct odict_entry *e = arg;
switch (e->type) {
case ODICT_OBJECT:
case ODICT_ARRAY:
mem_deref(e->u.odict);
break;
case ODICT_STRING:
mem_deref(e->u.str);
break;
default:
break;
}
hash_unlink(&e->he);
list_unlink(&e->le);
mem_deref(e->key);
}
int odict_entry_add(struct odict *o, const char *key,
enum odict_type type, ...)
{
struct odict_entry *e;
va_list ap;
int err;
if (!o || !key)
return EINVAL;
e = mem_zalloc(sizeof(*e), destructor);
if (!e)
return ENOMEM;
e->type = type;
err = str_dup(&e->key, key);
if (err)
goto out;
va_start(ap, type);
switch (e->type) {
case ODICT_OBJECT:
case ODICT_ARRAY:
e->u.odict = mem_ref(va_arg(ap, struct odict *));
break;
case ODICT_STRING:
err = str_dup(&e->u.str, va_arg(ap, const char *));
break;
case ODICT_INT:
e->u.integer = va_arg(ap, int64_t);
break;
case ODICT_DOUBLE:
e->u.dbl = va_arg(ap, double);
break;
case ODICT_BOOL:
e->u.boolean = va_arg(ap, int);
break;
case ODICT_NULL:
break;
default:
err = EINVAL;
break;
}
va_end(ap);
if (err)
goto out;
list_append(&o->lst, &e->le, e);
hash_append(o->ht, hash_fast_str(e->key), &e->he, e);
out:
if (err)
mem_deref(e);
return err;
}
int odict_entry_debug(struct re_printf *pf, const struct odict_entry *e)
{
int err;
if (!e)
return 0;
err = re_hprintf(pf, "%s", e->key);
switch (e->type) {
case ODICT_OBJECT:
case ODICT_ARRAY:
err |= re_hprintf(pf, ":%H", odict_debug, e->u.odict);
break;
case ODICT_STRING:
err |= re_hprintf(pf, ":%s", e->u.str);
break;
case ODICT_INT:
err |= re_hprintf(pf, ":%lli", e->u.integer);
break;
case ODICT_DOUBLE:
err |= re_hprintf(pf, ":%f", e->u.dbl);
break;
case ODICT_BOOL:
err |= re_hprintf(pf, ":%s", e->u.boolean ? "true" : "false");
break;
case ODICT_NULL:
break;
}
return err;
}

9
src/odict/mod.mk Normal file
View file

@ -0,0 +1,9 @@
#
# mod.mk
#
# Copyright (C) 2010 - 2015 Creytiv.com
#
SRCS += odict/entry.c
SRCS += odict/odict.c
SRCS += odict/type.c

124
src/odict/odict.c Normal file
View file

@ -0,0 +1,124 @@
/**
* @file odict.c Ordered Dictionary
*
* Copyright (C) 2010 Creytiv.com
*/
#include "re_types.h"
#include "re_fmt.h"
#include "re_mem.h"
#include "re_list.h"
#include "re_hash.h"
#include "re_odict.h"
static void destructor(void *arg)
{
struct odict *o = arg;
hash_clear(o->ht);
list_flush(&o->lst);
mem_deref(o->ht);
}
int odict_alloc(struct odict **op, uint32_t hash_size)
{
struct odict *o;
int err;
if (!op || !hash_size)
return EINVAL;
o = mem_zalloc(sizeof(*o), destructor);
if (!o)
return ENOMEM;
err = hash_alloc(&o->ht, hash_valid_size(hash_size));
if (err)
goto out;
out:
if (err)
mem_deref(o);
else
*op = o;
return err;
}
const struct odict_entry *odict_lookup(const struct odict *o, const char *key)
{
struct le *le;
if (!o || !key)
return NULL;
le = list_head(hash_list(o->ht, hash_fast_str(key)));
while (le) {
const struct odict_entry *e = le->data;
if (!str_cmp(e->key, key))
return e;
le = le->next;
}
return NULL;
}
size_t odict_count(const struct odict *o, bool nested)
{
struct le *le;
size_t n = 0;
if (!o)
return 0;
if (!nested)
return list_count(&o->lst);
for (le=o->lst.head; le; le=le->next) {
const struct odict_entry *e = le->data;
switch (e->type) {
case ODICT_OBJECT:
case ODICT_ARRAY:
n += odict_count(e->u.odict, true);
break;
default:
n += 1; /* count all entries */
break;
}
}
return n;
}
int odict_debug(struct re_printf *pf, const struct odict *o)
{
struct le *le;
int err;
if (!o)
return 0;
err = re_hprintf(pf, "{");
for (le=o->lst.head; le; le=le->next) {
const struct odict_entry *e = le->data;
err |= re_hprintf(pf, " %H", odict_entry_debug, e);
}
err |= re_hprintf(pf, " }");
return err;
}

59
src/odict/type.c Normal file
View file

@ -0,0 +1,59 @@
/**
* @file type.c Ordered Dictionary -- value types
*
* Copyright (C) 2010 - 2015 Creytiv.com
*/
#include "re_types.h"
#include "re_fmt.h"
#include "re_mem.h"
#include "re_list.h"
#include "re_hash.h"
#include "re_odict.h"
bool odict_type_iscontainer(enum odict_type type)
{
switch (type) {
case ODICT_OBJECT:
case ODICT_ARRAY:
return true;
default:
return false;
}
}
bool odict_type_isreal(enum odict_type type)
{
switch (type) {
case ODICT_STRING:
case ODICT_INT:
case ODICT_DOUBLE:
case ODICT_BOOL:
case ODICT_NULL:
return true;
default:
return false;
}
}
const char *odict_type_name(enum odict_type type)
{
switch (type) {
case ODICT_OBJECT: return "Object";
case ODICT_ARRAY: return "Array";
case ODICT_STRING: return "String";
case ODICT_INT: return "Integer";
case ODICT_DOUBLE: return "Double";
case ODICT_BOOL: return "Boolean";
case ODICT_NULL: return "Null";
default: return "???";
}
}