/** * @file NCDMethodIndex.c * @author Ambroz Bizjak * * @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 #include #include #include #include #include #include "NCDMethodIndex.h" #include "NCDMethodIndex_hash.h" #include #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 #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 #include static int 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 0; } 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 1; } static int 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 = -1; 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_EXECUTE(res) o->num_entries++; o->num_names++; if (out_entry_idx) { *out_entry_idx = name_entry->first_entry; } return 1; fail0: return 0; } int NCDMethodIndex_Init (NCDMethodIndex *o, NCDStringIndex *string_index) { ASSERT(string_index) o->string_index = string_index; 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); } NCDMethodIndex__Hash_Free(&o->hash); EntriesArray_Free(o); NamesArray_Free(o); } int NCDMethodIndex_AddMethod (NCDMethodIndex *o, const char *obj_type, size_t obj_type_len, const char *method_name, const struct NCDInterpModule *module) { ASSERT(obj_type) ASSERT(method_name) ASSERT(module) NCD_string_id_t obj_type_id = NCDStringIndex_GetBin(o->string_index, obj_type, obj_type_len); if (obj_type_id < 0) { BLog(BLOG_ERROR, "NCDStringIndex_Get failed"); goto fail0; } int entry_idx; int first_entry_idx; if (!find_method_name(o, method_name, &first_entry_idx)) { if (!add_method_name(o, method_name, &entry_idx)) { goto fail0; } ASSERT(entry_idx >= 0) ASSERT(entry_idx < o->num_entries) struct NCDMethodIndex__entry *entry = &o->entries[entry_idx]; entry->obj_type = obj_type_id; entry->module = module; } else { ASSERT(first_entry_idx >= 0) ASSERT(first_entry_idx < o->num_entries) if (o->num_entries == o->entries_capacity && !EntriesArray_DoubleUp(o)) { BLog(BLOG_ERROR, "EntriesArray_DoubleUp failed"); goto fail0; } entry_idx = o->num_entries; struct NCDMethodIndex__entry *entry = &o->entries[o->num_entries]; entry->obj_type = obj_type_id; entry->module = module; entry->next = o->entries[first_entry_idx].next; o->entries[first_entry_idx].next = o->num_entries; o->num_entries++; } return entry_idx; fail0: return -1; } void NCDMethodIndex_RemoveMethod (NCDMethodIndex *o, int method_name_id) { ASSERT(method_name_id >= 0) ASSERT(method_name_id < o->num_entries) ASSERT(o->entries[method_name_id].obj_type >= 0) o->entries[method_name_id].obj_type = -1; } 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 NCDInterpModule * NCDMethodIndex_GetMethodModule (NCDMethodIndex *o, NCD_string_id_t obj_type, int method_name_id) { ASSERT(obj_type >= 0) 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 == 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; }