diff options
Diffstat (limited to 'src/symap.c')
-rw-r--r-- | src/symap.c | 343 |
1 files changed, 178 insertions, 165 deletions
diff --git a/src/symap.c b/src/symap.c index afcdadb..07002f2 100644 --- a/src/symap.c +++ b/src/symap.c @@ -1,18 +1,5 @@ -/* - Copyright 2011-2014 David Robillard <http://drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2022 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #include "symap.h" @@ -38,56 +25,47 @@ */ struct SymapImpl { - /** - Unsorted array of strings, such that the symbol for ID i is found - at symbols[i - 1]. - */ - char** symbols; - - /** - Array of IDs, sorted by corresponding string in `symbols`. - */ - uint32_t* index; - - /** - Number of symbols (number of items in `symbols` and `index`). - */ - uint32_t size; + char** symbols; ///< String array where symbols[i] is the symbol for ID i + uint32_t* index; ///< ID array sorted by corresponding string in `symbols` + uint32_t size; ///< Number of symbols (length of both symbols and index) + uint32_t pad; ///< Unused padding }; Symap* symap_new(void) { - Symap* map = (Symap*)malloc(sizeof(Symap)); - map->symbols = NULL; - map->index = NULL; - map->size = 0; - return map; + Symap* const map = (Symap*)calloc(1, sizeof(Symap)); + + if (map) { + map->symbols = NULL; + map->index = NULL; + map->size = 0U; + } + + return map; } void -symap_free(Symap* map) +symap_free(Symap* const map) { - if (!map) { - return; - } - - for (uint32_t i = 0; i < map->size; ++i) { - free(map->symbols[i]); - } - - free(map->symbols); - free(map->index); - free(map); + if (map) { + for (uint32_t i = 0U; i < map->size; ++i) { + free(map->symbols[i]); + } + + free(map->symbols); + free(map->index); + free(map); + } } static char* -symap_strdup(const char* str) +symap_strdup(const char* const str) { - const size_t len = strlen(str); - char* copy = (char*)malloc(len + 1); - memcpy(copy, str, len + 1); - return copy; + const size_t len = strlen(str); + char* const copy = (char*)malloc(len + 1); + memcpy(copy, str, len + 1); + return copy; } /** @@ -95,141 +73,176 @@ symap_strdup(const char* str) or the index where a new entry for `sym` should be inserted. */ static uint32_t -symap_search(const Symap* map, const char* sym, bool* exact) +symap_search(const Symap* const map, const char* const sym, bool* const exact) { - *exact = false; - if (map->size == 0) { - return 0; // Empty map, insert at 0 - } else if (strcmp(map->symbols[map->index[map->size - 1] - 1], sym) < 0) { - return map->size; // Greater than last element, append - } - - uint32_t lower = 0; - uint32_t upper = map->size - 1; - uint32_t i = upper; - int cmp; - - while (upper >= lower) { - i = lower + ((upper - lower) / 2); - cmp = strcmp(map->symbols[map->index[i] - 1], sym); - - if (cmp == 0) { - *exact = true; - return i; - } else if (cmp > 0) { - if (i == 0) { - break; // Avoid underflow - } - upper = i - 1; - } else { - lower = ++i; - } - } - - assert(!*exact || strcmp(map->symbols[map->index[i] - 1], sym) > 0); - return i; + *exact = false; + + if (map->size == 0) { + return 0; // Empty map, insert at 0 + } + + if (strcmp(map->symbols[map->index[map->size - 1] - 1], sym) < 0) { + return map->size; // Greater than last element, append + } + + uint32_t lower = 0; + uint32_t upper = map->size - 1; + uint32_t i = upper; + int cmp = 0; + + while (upper >= lower) { + i = lower + ((upper - lower) / 2); + cmp = strcmp(map->symbols[map->index[i] - 1], sym); + + if (cmp == 0) { + *exact = true; + return i; + } + + if (cmp > 0) { + if (i == 0) { + break; // Avoid underflow + } + upper = i - 1; + } else { + lower = ++i; + } + } + + assert(!*exact || strcmp(map->symbols[map->index[i] - 1], sym) > 0); + return i; } uint32_t -symap_try_map(Symap* map, const char* sym) +symap_try_map(const Symap* const map, const char* const sym) { - bool exact; - const uint32_t index = symap_search(map, sym, &exact); - if (exact) { - assert(!strcmp(map->symbols[map->index[index]], sym)); - return map->index[index]; - } - - return 0; + bool exact = false; + const uint32_t index = symap_search(map, sym, &exact); + if (exact) { + return map->index[index]; + } + + return 0; } uint32_t -symap_map(Symap* map, const char* sym) +symap_map(Symap* const map, const char* sym) { - bool exact; - const uint32_t index = symap_search(map, sym, &exact); - if (exact) { - assert(!strcmp(map->symbols[map->index[index] - 1], sym)); - return map->index[index]; - } - - const uint32_t id = ++map->size; - char* const str = symap_strdup(sym); - - /* Append new symbol to symbols array */ - map->symbols = (char**)realloc(map->symbols, map->size * sizeof(str)); - map->symbols[id - 1] = str; - - /* Insert new index element into sorted index */ - map->index = (uint32_t*)realloc(map->index, map->size * sizeof(uint32_t)); - if (index < map->size - 1) { - memmove(map->index + index + 1, - map->index + index, - (map->size - index - 1) * sizeof(uint32_t)); - } - - map->index[index] = id; - - return id; + // Search for existing symbol + bool exact = false; + const uint32_t index = symap_search(map, sym, &exact); + if (exact) { + assert(!strcmp(map->symbols[map->index[index] - 1], sym)); + return map->index[index]; + } + + // Claim a new highest ID + const uint32_t id = map->size + 1; + + // Grow symbol array + char** new_symbols = (char**)realloc(map->symbols, id * sizeof(sym)); + if (!new_symbols) { + return 0; + } + + map->symbols = new_symbols; + + // Grow index array + uint32_t* new_index = (uint32_t*)realloc(map->index, id * sizeof(index)); + if (!new_index) { + return 0; + } + + map->index = new_index; + + // Append new symbol to symbols array + map->size = id; + map->symbols[id - 1] = symap_strdup(sym); + + // Insert new index element into sorted index + map->index = new_index; + if (index < map->size - 1) { + memmove(map->index + index + 1, + map->index + index, + (map->size - index - 1) * sizeof(uint32_t)); + } + + map->index[index] = id; + + return id; } const char* -symap_unmap(Symap* map, uint32_t id) +symap_unmap(const Symap* const map, const uint32_t id) { - if (id == 0) { - return NULL; - } else if (id <= map->size) { - return map->symbols[id - 1]; - } - return NULL; + if (id == 0) { + return NULL; + } + + if (id <= map->size) { + return map->symbols[id - 1]; + } + + return NULL; } -#ifdef STANDALONE +#ifdef SYMAP_STANDALONE -#include <stdio.h> +# include <stdio.h> static void -symap_dump(Symap* map) +symap_dump(Symap* const map) +{ + fprintf(stderr, "{\n"); + for (uint32_t i = 0; i < map->size; ++i) { + fprintf( + stderr, "\t%u = %s\n", map->index[i], map->symbols[map->index[i] - 1]); + } + fprintf(stderr, "}\n"); +} + +static int +symap_test(Symap* const map) { - fprintf(stderr, "{\n"); - for (uint32_t i = 0; i < map->size; ++i) { - fprintf(stderr, "\t%u = %s\n", - map->index[i], map->symbols[map->index[i] - 1]); - } - fprintf(stderr, "}\n"); +# define N_SYMS 5 + + static const char* const syms[N_SYMS] = { + "hello", "bonjour", "goodbye", "aloha", "salut"}; + + for (int i = 0; i < N_SYMS; ++i) { + if (symap_try_map(map, syms[i])) { + return fprintf(stderr, "error: Symbol already mapped\n"); + } + + const uint32_t id = symap_map(map, syms[i]); + if (!id) { + return fprintf(stderr, "error: Failed to insert ID\n"); + } + + if (!!strcmp(map->symbols[id - 1], syms[i])) { + return fprintf(stderr, "error: Corrupt symbol table\n"); + } + + if (symap_map(map, syms[i]) != id) { + return fprintf(stderr, "error: Remapped symbol to a different ID\n"); + } + + symap_dump(map); + } + + return 0; + +# undef N_SYMS } int -main() +main(void) { - #define N_SYMS 5 - char* syms[N_SYMS] = { - "hello", "bonjour", "goodbye", "aloha", "salut" - }; - - Symap* map = symap_new(); - for (int i = 0; i < N_SYMS; ++i) { - if (symap_try_map(map, syms[i])) { - fprintf(stderr, "error: Symbol already mapped\n"); - return 1; - } - - const uint32_t id = symap_map(map, syms[i]); - if (strcmp(map->symbols[id - 1], syms[i])) { - fprintf(stderr, "error: Corrupt symbol table\n"); - return 1; - } - - if (symap_map(map, syms[i]) != id) { - fprintf(stderr, "error: Remapped symbol to a different ID\n"); - return 1; - } - - symap_dump(map); - } - - symap_free(map); - return 0; + Symap* const map = symap_new(); + const int st = symap_test(map); + + symap_free(map); + return st; } -#endif /* STANDALONE */ +#endif // SYMAP_STANDALONE |