int tsm_symbol_table_new(struct tsm_symbol_table **out) { struct tsm_symbol_table *tbl; int ret; static const uint32_t *val = NULL; /* we need a valid lvalue */ if (!out) return -EINVAL; tbl = malloc(sizeof(*tbl)); if (!tbl) return -ENOMEM; memset(tbl, 0, sizeof(*tbl)); tbl->ref = 1; tbl->next_id = TSM_UCS4_MAX + 2; shl_htable_init(&tbl->symbols, cmp_ucs4, hash_ucs4, NULL); ret = shl_array_new(&tbl->index, sizeof(uint32_t*), 4); if (ret) goto err_free; /* first entry is not used so add dummy */ shl_array_push(tbl->index, &val); *out = tbl; return 0; err_free: free(tbl); return ret; }
tsm_symbol_t tsm_symbol_append(struct tsm_symbol_table *tbl, tsm_symbol_t sym, uint32_t ucs4) { uint32_t buf[TSM_UCS4_MAXLEN + 1], nsym, *nval; const uint32_t *ptr; size_t s; bool res; int ret; if (!tbl) return sym; if (ucs4 > TSM_UCS4_MAX) return sym; ptr = tsm_symbol_get(tbl, &sym, &s); if (s >= TSM_UCS4_MAXLEN) return sym; memcpy(buf, ptr, s * sizeof(uint32_t)); buf[s++] = ucs4; buf[s++] = TSM_UCS4_MAX + 1; res = shl_htable_lookup(&tbl->symbols, buf, hash_ucs4(buf, NULL), (void**)&nval); if (res) { /* key is prefixed with actual value */ return *--nval; } /* We save the key in nval and prefix it with the new ID. Note that * the prefix is hidden, we actually store "++nval" in the htable. */ nval = malloc(sizeof(uint32_t) * (s + 1)); if (!nval) return sym; ++nval; memcpy(nval, buf, s * sizeof(uint32_t)); nsym = tbl->next_id + 1; /* Out of IDs; we actually have 2 Billion IDs so this seems * very unlikely but lets be safe here */ if (nsym <= tbl->next_id++) goto err_id; /* store ID hidden before the key */ *(nval - 1) = nsym; ret = shl_htable_insert(&tbl->symbols, nval, hash_ucs4(nval, NULL)); if (ret) goto err_id; ret = shl_array_push(tbl->index, &nval); if (ret) goto err_symbol; return nsym; err_symbol: shl_htable_remove(&tbl->symbols, nval, hash_ucs4(nval, NULL), NULL); err_id: --tbl->next_id; free(nval); return sym; }
SHL_EXPORT tsm_symbol_t tsm_symbol_append(struct tsm_symbol_table *tbl, tsm_symbol_t sym, uint32_t ucs4) { uint32_t buf[TSM_UCS4_MAXLEN + 1], nsym, *nval; const uint32_t *ptr; size_t s; void *tmp; bool res; int ret; if (!tbl) tbl = tsm_symbol_table_default; if (!tbl) { ret = tsm_symbol_table_new(&tbl); if (ret) return sym; tsm_symbol_table_default = tbl; } if (ucs4 > TSM_UCS4_MAX) return sym; ptr = tsm_symbol_get(tbl, &sym, &s); if (s >= TSM_UCS4_MAXLEN) return sym; memcpy(buf, ptr, s * sizeof(uint32_t)); buf[s++] = ucs4; buf[s++] = TSM_UCS4_MAX + 1; res = shl_hashtable_find(tbl->symbols, &tmp, buf); if (res) return (uint32_t)(long)tmp; nval = malloc(sizeof(uint32_t) * s); if (!nval) return sym; memcpy(nval, buf, s * sizeof(uint32_t)); nsym = tbl->next_id + 1; /* Out of IDs; we actually have 2 Billion IDs so this seems * very unlikely but lets be safe here */ if (nsym <= tbl->next_id++) goto err_id; ret = shl_hashtable_insert(tbl->symbols, nval, (void*)(long)nsym); if (ret) goto err_id; ret = shl_array_push(tbl->index, &nval); if (ret) goto err_symbol; return nsym; err_symbol: shl_hashtable_remove(tbl->symbols, nval); err_id: --tbl->next_id; free(nval); return sym; }