add odict
This commit is contained in:
parent
e16054be2c
commit
9ff337301d
9 changed files with 619 additions and 0 deletions
1
Makefile
1
Makefile
|
@ -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),)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
44
include/re_odict.h
Normal 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);
|
233
src/hash/func.c
233
src/hash/func.c
|
@ -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
146
src/odict/entry.c
Normal 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
9
src/odict/mod.mk
Normal 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
124
src/odict/odict.c
Normal 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
59
src/odict/type.c
Normal 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 "???";
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue