/** * @file NCDStringIndex.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 "NCDStringIndex.h" #include "NCDStringIndex_hash.h" #include #define GROWARRAY_NAME Array #define GROWARRAY_OBJECT_TYPE NCDStringIndex #define GROWARRAY_ARRAY_MEMBER entries #define GROWARRAY_CAPACITY_MEMBER entries_capacity #define GROWARRAY_MAX_CAPACITY NCD_STRING_ID_MAX #include #include // NOTE: keep synchronized with static_strings.h static const char *static_strings[] = { "", "_args", "_arg0", "_arg1", "_arg2", "_arg3", "_arg4", "_arg5", "_arg6", "_arg7", "_arg8", "_arg9", "_arg10", "_arg11", "_arg12", "_arg13", "_arg14", "_arg15", "_arg16", "_arg17", "_arg18", "_arg19", "true", "false", "", "_caller", "succeeded", "is_error", "not_eof", "length", "type", "exit_status", "size" }; static NCD_string_id_t do_get (NCDStringIndex *o, const char *str, size_t str_len) { ASSERT(str) NCDStringIndex_hash_key key = {str, str_len}; NCDStringIndex__HashRef ref = NCDStringIndex__Hash_Lookup(&o->hash, o->entries, key); ASSERT(ref.link == -1 || ref.link >= 0) ASSERT(ref.link == -1 || ref.link < o->entries_size) ASSERT(ref.link == -1 || (ref.ptr->str_len == str_len && !memcmp(ref.ptr->str, str, str_len))) if (ref.link != -1) { return ref.link; } if (o->entries_size == o->entries_capacity) { if (!Array_DoubleUp(o)) { BLog(BLOG_ERROR, "Array_DoubleUp failed"); return -1; } if (!NCDStringIndex__Hash_MultiplyBuckets(&o->hash, o->entries, 1)) { BLog(BLOG_ERROR, "NCDStringIndex__Hash_MultiplyBuckets failed"); return -1; } } ASSERT(o->entries_size < o->entries_capacity) struct NCDStringIndex__entry *entry = &o->entries[o->entries_size]; if (!(entry->str = b_strdup_bin(str, str_len))) { BLog(BLOG_ERROR, "b_strdup_bin failed"); return -1; } entry->str_len = str_len; entry->has_nulls = !!memchr(str, '\0', str_len); NCDStringIndex__HashRef newref = {entry, o->entries_size}; int res = NCDStringIndex__Hash_Insert(&o->hash, o->entries, newref, NULL); ASSERT_EXECUTE(res) return o->entries_size++; } int NCDStringIndex_Init (NCDStringIndex *o) { o->entries_size = 0; if (!Array_Init(o, NCDSTRINGINDEX_INITIAL_CAPACITY)) { BLog(BLOG_ERROR, "Array_Init failed"); goto fail0; } if (!NCDStringIndex__Hash_Init(&o->hash, NCDSTRINGINDEX_INITIAL_HASH_BUCKETS)) { BLog(BLOG_ERROR, "NCDStringIndex__Hash_Init failed"); goto fail1; } for (size_t i = 0; i < B_ARRAY_LENGTH(static_strings); i++) { if (do_get(o, static_strings[i], strlen(static_strings[i])) < 0) { goto fail2; } } DebugObject_Init(&o->d_obj); return 1; fail2: for (NCD_string_id_t i = 0; i < o->entries_size; i++) { free(o->entries[i].str); } NCDStringIndex__Hash_Free(&o->hash); fail1: Array_Free(o); fail0: return 0; } void NCDStringIndex_Free (NCDStringIndex *o) { DebugObject_Free(&o->d_obj); for (NCD_string_id_t i = 0; i < o->entries_size; i++) { free(o->entries[i].str); } NCDStringIndex__Hash_Free(&o->hash); Array_Free(o); } NCD_string_id_t NCDStringIndex_Lookup (NCDStringIndex *o, const char *str) { DebugObject_Access(&o->d_obj); ASSERT(str) return NCDStringIndex_LookupBin(o, str, strlen(str)); } NCD_string_id_t NCDStringIndex_LookupBin (NCDStringIndex *o, const char *str, size_t str_len) { DebugObject_Access(&o->d_obj); ASSERT(str) NCDStringIndex_hash_key key = {str, str_len}; NCDStringIndex__HashRef ref = NCDStringIndex__Hash_Lookup(&o->hash, o->entries, key); ASSERT(ref.link == -1 || ref.link >= 0) ASSERT(ref.link == -1 || ref.link < o->entries_size) ASSERT(ref.link == -1 || (ref.ptr->str_len == str_len && !memcmp(ref.ptr->str, str, str_len))) return ref.link; } NCD_string_id_t NCDStringIndex_Get (NCDStringIndex *o, const char *str) { DebugObject_Access(&o->d_obj); ASSERT(str) return NCDStringIndex_GetBin(o, str, strlen(str)); } NCD_string_id_t NCDStringIndex_GetBin (NCDStringIndex *o, const char *str, size_t str_len) { DebugObject_Access(&o->d_obj); ASSERT(str) return do_get(o, str, str_len); } const char * NCDStringIndex_Value (NCDStringIndex *o, NCD_string_id_t id) { DebugObject_Access(&o->d_obj); ASSERT(id >= 0) ASSERT(id < o->entries_size) ASSERT(o->entries[id].str) return o->entries[id].str; } size_t NCDStringIndex_Length (NCDStringIndex *o, NCD_string_id_t id) { DebugObject_Access(&o->d_obj); ASSERT(id >= 0) ASSERT(id < o->entries_size) ASSERT(o->entries[id].str) return o->entries[id].str_len; } int NCDStringIndex_HasNulls (NCDStringIndex *o, NCD_string_id_t id) { DebugObject_Access(&o->d_obj); ASSERT(id >= 0) ASSERT(id < o->entries_size) ASSERT(o->entries[id].str) return o->entries[id].has_nulls; } int NCDStringIndex_GetRequests (NCDStringIndex *o, struct NCD_string_request *requests) { DebugObject_Access(&o->d_obj); ASSERT(requests) while (requests->str) { NCD_string_id_t id = NCDStringIndex_Get(o, requests->str); if (id < 0) { return 0; } requests->id = id; requests++; } return 1; }