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 "???";
+ }
+}