LeOS-Genesis/external/badvpn/ncd/NCDMethodIndex.c

273 lines
8.0 KiB
C
Raw Normal View History

2020-10-05 13:12:00 +02:00
/**
* @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 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;
}