Squashed 'third_party/rawrtc/re/' content from commit f3163ce8b

Change-Id: I6a235e6ac0f03269d951026f9d195da05c40fdab
git-subtree-dir: third_party/rawrtc/re
git-subtree-split: f3163ce8b526a13b35ef71ce4dd6f43585064d8a
diff --git a/src/odict/entry.c b/src/odict/entry.c
new file mode 100644
index 0000000..53daf2b
--- /dev/null
+++ b/src/odict/entry.c
@@ -0,0 +1,152 @@
+/**
+ * @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,
+		    int 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;
+}
+
+
+void odict_entry_del(struct odict *o, const char *key)
+{
+	mem_deref((struct odict_entry *)odict_lookup(o, key));
+}
+
+
+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;
+}
diff --git a/src/odict/get.c b/src/odict/get.c
new file mode 100644
index 0000000..816a805
--- /dev/null
+++ b/src/odict/get.c
@@ -0,0 +1,89 @@
+/**
+ * @file get.c  Ordered Dictionary -- high level accessors
+ *
+ * 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"
+
+
+const struct odict_entry *odict_get_type(const struct odict *o,
+					 enum odict_type type, const char *key)
+{
+	const struct odict_entry *entry;
+
+	if (!o || !key)
+		return NULL;
+
+	entry = odict_lookup(o, key);
+	if (!entry)
+		return NULL;
+
+	if (entry->type != type)
+		return NULL;
+
+	return entry;
+}
+
+
+const char *odict_string(const struct odict *o, const char *key)
+{
+	const struct odict_entry *entry;
+
+	entry = odict_get_type(o, ODICT_STRING, key);
+	if (!entry)
+		return NULL;
+
+	return entry->u.str;
+}
+
+
+bool odict_get_number(const struct odict *o, uint64_t *num, const char *key)
+{
+	const struct odict_entry *entry;
+
+	if (!o || !key)
+		return false;
+
+	entry = odict_lookup(o, key);
+	if (!entry)
+		return false;
+
+	switch (entry->type) {
+
+	case ODICT_DOUBLE:
+		if (num)
+			*num = (uint64_t)entry->u.dbl;
+		break;
+
+	case ODICT_INT:
+		if (num)
+			*num = entry->u.integer;
+		break;
+
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+
+bool odict_get_boolean(const struct odict *o, bool *value, const char *key)
+{
+	const struct odict_entry *entry;
+
+	entry = odict_get_type(o, ODICT_BOOL, key);
+	if (!entry)
+		return false;
+
+	if (value)
+		*value = entry->u.boolean;
+
+	return true;
+}
diff --git a/src/odict/mod.mk b/src/odict/mod.mk
new file mode 100644
index 0000000..74023a3
--- /dev/null
+++ b/src/odict/mod.mk
@@ -0,0 +1,10 @@
+#
+# mod.mk
+#
+# Copyright (C) 2010 - 2015 Creytiv.com
+#
+
+SRCS	+= odict/entry.c
+SRCS	+= odict/odict.c
+SRCS	+= odict/type.c
+SRCS	+= odict/get.c
diff --git a/src/odict/odict.c b/src/odict/odict.c
new file mode 100644
index 0000000..8e87968
--- /dev/null
+++ b/src/odict/odict.c
@@ -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;
+}
diff --git a/src/odict/type.c b/src/odict/type.c
new file mode 100644
index 0000000..bb0dab9
--- /dev/null
+++ b/src/odict/type.c
@@ -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 "???";
+	}
+}