|
|
@@ -0,0 +1,256 @@
|
|
|
+/**
|
|
|
+ * @file NCDMethodIndex.c
|
|
|
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
|
|
|
+ *
|
|
|
+ * @section LICENSE
|
|
|
+ *
|
|
|
+ * Redistribution and use in source and binary forms, with or without
|
|
|
+ * modification, are permitted provided that the following conditions are met:
|
|
|
+ * 1. Redistributions of source code must retain the above copyright
|
|
|
+ * notice, this list of conditions and the following disclaimer.
|
|
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
|
|
+ * notice, this list of conditions and the following disclaimer in the
|
|
|
+ * documentation and/or other materials provided with the distribution.
|
|
|
+ * 3. Neither the name of the author nor the
|
|
|
+ * names of its contributors may be used to endorse or promote products
|
|
|
+ * derived from this software without specific prior written permission.
|
|
|
+ *
|
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
|
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
|
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
|
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
+ */
|
|
|
+
|
|
|
+#include <string.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <limits.h>
|
|
|
+
|
|
|
+#include <misc/hashfun.h>
|
|
|
+#include <misc/balloc.h>
|
|
|
+#include <misc/strdup.h>
|
|
|
+
|
|
|
+#include "NCDMethodIndex.h"
|
|
|
+
|
|
|
+#include "NCDMethodIndex_hash.h"
|
|
|
+#include <structure/CHash_impl.h>
|
|
|
+
|
|
|
+#define GROWARRAY_NAME NamesArray
|
|
|
+#define GROWARRAY_OBJECT_TYPE NCDMethodIndex
|
|
|
+#define GROWARRAY_ARRAY_MEMBER names
|
|
|
+#define GROWARRAY_CAPACITY_MEMBER names_capacity
|
|
|
+#define GROWARRAY_MAX_CAPACITY INT_MAX
|
|
|
+#include <misc/grow_array.h>
|
|
|
+
|
|
|
+#define GROWARRAY_NAME EntriesArray
|
|
|
+#define GROWARRAY_OBJECT_TYPE NCDMethodIndex
|
|
|
+#define GROWARRAY_ARRAY_MEMBER entries
|
|
|
+#define GROWARRAY_CAPACITY_MEMBER entries_capacity
|
|
|
+#define GROWARRAY_MAX_CAPACITY INT_MAX
|
|
|
+#include <misc/grow_array.h>
|
|
|
+
|
|
|
+#include <generated/blog_channel_ncd.h>
|
|
|
+
|
|
|
+static struct NCDMethodIndex__entry * find_method_name (NCDMethodIndex *o, const char *method_name, int *out_entry_idx)
|
|
|
+{
|
|
|
+ ASSERT(method_name)
|
|
|
+
|
|
|
+ NCDMethodIndex__HashRef ref = NCDMethodIndex__Hash_Lookup(&o->hash, o->names, method_name);
|
|
|
+ if (ref.link == -1) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ ASSERT(ref.link >= 0)
|
|
|
+ ASSERT(ref.link < o->num_names)
|
|
|
+
|
|
|
+ struct NCDMethodIndex__method_name *name_entry = ref.ptr;
|
|
|
+ ASSERT(!strcmp(name_entry->method_name, method_name))
|
|
|
+ ASSERT(name_entry->first_entry >= 0)
|
|
|
+ ASSERT(name_entry->first_entry < o->num_entries)
|
|
|
+
|
|
|
+ if (out_entry_idx) {
|
|
|
+ *out_entry_idx = name_entry->first_entry;
|
|
|
+ }
|
|
|
+ return &o->entries[name_entry->first_entry];
|
|
|
+}
|
|
|
+
|
|
|
+static struct NCDMethodIndex__entry * add_method_name (NCDMethodIndex *o, const char *method_name, int *out_entry_idx)
|
|
|
+{
|
|
|
+ ASSERT(method_name)
|
|
|
+ ASSERT(!find_method_name(o, method_name, NULL))
|
|
|
+
|
|
|
+ if (o->num_entries == o->entries_capacity && !EntriesArray_DoubleUp(o)) {
|
|
|
+ BLog(BLOG_ERROR, "EntriesArray_DoubleUp failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (o->num_names == o->names_capacity && !NamesArray_DoubleUp(o)) {
|
|
|
+ BLog(BLOG_ERROR, "NamesArray_DoubleUp failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ struct NCDMethodIndex__entry *entry = &o->entries[o->num_entries];
|
|
|
+ entry->obj_type = NULL;
|
|
|
+ entry->next = -1;
|
|
|
+
|
|
|
+ struct NCDMethodIndex__method_name *name_entry = &o->names[o->num_names];
|
|
|
+
|
|
|
+ if (!(name_entry->method_name = b_strdup(method_name))) {
|
|
|
+ BLog(BLOG_ERROR, "b_strdup failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ name_entry->first_entry = o->num_entries;
|
|
|
+
|
|
|
+ NCDMethodIndex__HashRef ref = {name_entry, o->num_names};
|
|
|
+ int res = NCDMethodIndex__Hash_Insert(&o->hash, o->names, ref, NULL);
|
|
|
+ ASSERT(res)
|
|
|
+
|
|
|
+ o->num_entries++;
|
|
|
+ o->num_names++;
|
|
|
+
|
|
|
+ if (out_entry_idx) {
|
|
|
+ *out_entry_idx = name_entry->first_entry;
|
|
|
+ }
|
|
|
+ return entry;
|
|
|
+
|
|
|
+fail0:
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+int NCDMethodIndex_Init (NCDMethodIndex *o)
|
|
|
+{
|
|
|
+ if (!NamesArray_Init(o, NCDMETHODINDEX_NUM_EXPECTED_METHOD_NAMES)) {
|
|
|
+ BLog(BLOG_ERROR, "NamesArray_Init failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!EntriesArray_Init(o, NCDMETHODINDEX_NUM_EXPECTED_ENTRIES)) {
|
|
|
+ BLog(BLOG_ERROR, "EntriesArray_Init failed");
|
|
|
+ goto fail1;
|
|
|
+ }
|
|
|
+
|
|
|
+ o->num_names = 0;
|
|
|
+ o->num_entries = 0;
|
|
|
+
|
|
|
+ if (!NCDMethodIndex__Hash_Init(&o->hash, NCDMETHODINDEX_NUM_EXPECTED_METHOD_NAMES)) {
|
|
|
+ BLog(BLOG_ERROR, "NCDMethodIndex__Hash_Init failed");
|
|
|
+ goto fail2;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+
|
|
|
+fail2:
|
|
|
+ EntriesArray_Free(o);
|
|
|
+fail1:
|
|
|
+ NamesArray_Free(o);
|
|
|
+fail0:
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void NCDMethodIndex_Free (NCDMethodIndex *o)
|
|
|
+{
|
|
|
+ for (int i = 0; i < o->num_names; i++) {
|
|
|
+ free(o->names[i].method_name);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < o->num_entries; i++) {
|
|
|
+ free(o->entries[i].obj_type);
|
|
|
+ }
|
|
|
+
|
|
|
+ NCDMethodIndex__Hash_Free(&o->hash);
|
|
|
+ EntriesArray_Free(o);
|
|
|
+ NamesArray_Free(o);
|
|
|
+}
|
|
|
+
|
|
|
+int NCDMethodIndex_AddMethod (NCDMethodIndex *o, const char *obj_type, const char *method_name, const struct NCDModule *module)
|
|
|
+{
|
|
|
+ ASSERT(obj_type)
|
|
|
+ ASSERT(method_name)
|
|
|
+ ASSERT(module)
|
|
|
+
|
|
|
+ struct NCDMethodIndex__entry *first_entry = find_method_name(o, method_name, NULL);
|
|
|
+
|
|
|
+ if (!first_entry) {
|
|
|
+ struct NCDMethodIndex__entry *entry = add_method_name(o, method_name, NULL);
|
|
|
+ if (!entry) {
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(entry->obj_type = b_strdup(obj_type))) {
|
|
|
+ BLog(BLOG_ERROR, "b_strdup failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ entry->module = module;
|
|
|
+ } else {
|
|
|
+ if (o->num_entries == o->entries_capacity && !EntriesArray_DoubleUp(o)) {
|
|
|
+ BLog(BLOG_ERROR, "EntriesArray_DoubleUp failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ struct NCDMethodIndex__entry *entry = &o->entries[o->num_entries];
|
|
|
+
|
|
|
+ if (!(entry->obj_type = b_strdup(obj_type))) {
|
|
|
+ BLog(BLOG_ERROR, "b_strdup failed");
|
|
|
+ goto fail0;
|
|
|
+ }
|
|
|
+
|
|
|
+ entry->module = module;
|
|
|
+
|
|
|
+ entry->next = first_entry->next;
|
|
|
+ first_entry->next = o->num_entries;
|
|
|
+
|
|
|
+ o->num_entries++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 1;
|
|
|
+
|
|
|
+fail0:
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int NCDMethodIndex_GetMethodNameId (NCDMethodIndex *o, const char *method_name)
|
|
|
+{
|
|
|
+ ASSERT(method_name)
|
|
|
+
|
|
|
+ int first_entry_idx;
|
|
|
+
|
|
|
+ if (!find_method_name(o, method_name, &first_entry_idx)) {
|
|
|
+ if (!add_method_name(o, method_name, &first_entry_idx)) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ASSERT(first_entry_idx >= 0)
|
|
|
+ ASSERT(first_entry_idx < o->num_entries)
|
|
|
+
|
|
|
+ return first_entry_idx;
|
|
|
+}
|
|
|
+
|
|
|
+const struct NCDModule * NCDMethodIndex_GetMethodModule (NCDMethodIndex *o, const char *obj_type, int method_name_id)
|
|
|
+{
|
|
|
+ ASSERT(obj_type)
|
|
|
+ ASSERT(method_name_id >= 0)
|
|
|
+ ASSERT(method_name_id < o->num_entries)
|
|
|
+
|
|
|
+ do {
|
|
|
+ struct NCDMethodIndex__entry *entry = &o->entries[method_name_id];
|
|
|
+
|
|
|
+ if (entry->obj_type && !strcmp(entry->obj_type, obj_type)) {
|
|
|
+ ASSERT(entry->module)
|
|
|
+ return entry->module;
|
|
|
+ }
|
|
|
+
|
|
|
+ method_name_id = entry->next;
|
|
|
+ ASSERT(method_name_id >= -1)
|
|
|
+ ASSERT(method_name_id < o->num_entries)
|
|
|
+ } while (method_name_id >= 0);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|