static void da_relocate_base (DArray *d, TrieIndex s, TrieIndex new_base) { TrieIndex old_base; Symbols *symbols; int i; old_base = da_get_base (d, s); symbols = da_output_symbols (d, s); for (i = 0; i < symbols_num (symbols); i++) { TrieIndex old_next, new_next, old_next_base; old_next = old_base + symbols_get (symbols, i); new_next = new_base + symbols_get (symbols, i); old_next_base = da_get_base (d, old_next); /* allocate new next node and copy BASE value */ da_alloc_cell (d, new_next); da_set_check (d, new_next, s); da_set_base (d, new_next, old_next_base); /* old_next node is now moved to new_next * so, all cells belonging to old_next * must be given to new_next */ /* preventing the case of TAIL pointer */ if (old_next_base > 0) { TrieIndex c, max_c; max_c = MIN_VAL (TRIE_CHAR_MAX, TRIE_INDEX_MAX - old_next_base); for (c = 0; c < max_c; c++) { if (da_get_check (d, old_next_base + c) == old_next) da_set_check (d, old_next_base + c, new_next); } } /* free old_next node */ da_free_cell (d, old_next); } symbols_free (symbols); /* finally, make BASE[s] point to new_base */ da_set_base (d, s, new_base); }
static void da_free_cell (DArray *d, TrieIndex cell) { TrieIndex i, prev; /* find insertion point */ i = -da_get_check (d, da_get_free_list (d)); while (i != da_get_free_list (d) && i < cell) i = -da_get_check (d, i); prev = -da_get_base (d, i); /* insert cell before i */ da_set_check (d, cell, -i); da_set_base (d, cell, -prev); da_set_check (d, prev, -cell); da_set_base (d, i, -cell); }
/** * @brief Insert a branch from trie node * * @param d : the double-array structure * @param s : the state to add branch to * @param c : the character for the branch label * * @return the index of the new node * * Insert a new arc labelled with character @a c from the trie node * represented by index @a s in double-array structure @a d. * Note that it assumes that no such arc exists before inserting. */ TrieIndex da_insert_branch (DArray *d, TrieIndex s, TrieChar c) { TrieIndex base, next; base = da_get_base (d, s); if (base > 0) { next = base + c; /* if already there, do not actually insert */ if (da_get_check (d, next) == s) return next; /* if (base + c) > TRIE_INDEX_MAX which means 'next' is overflow, * or cell [next] is not free, relocate to a free slot */ if (base > TRIE_INDEX_MAX - c || !da_check_free_cell (d, next)) { Symbols *symbols; TrieIndex new_base; /* relocate BASE[s] */ symbols = da_output_symbols (d, s); symbols_add (symbols, c); new_base = da_find_free_base (d, symbols); symbols_free (symbols); if (TRIE_INDEX_ERROR == new_base) return TRIE_INDEX_ERROR; da_relocate_base (d, s, new_base); next = new_base + c; } } else { Symbols *symbols; TrieIndex new_base; symbols = symbols_new (); symbols_add (symbols, c); new_base = da_find_free_base (d, symbols); symbols_free (symbols); if (TRIE_INDEX_ERROR == new_base) return TRIE_INDEX_ERROR; da_set_base (d, s, new_base); next = new_base + c; } da_alloc_cell (d, next); da_set_check (d, next, s); return next; }
static void da_alloc_cell (DArray *d, TrieIndex cell) { TrieIndex prev, next; prev = -da_get_base (d, cell); next = -da_get_check (d, cell); /* remove the cell from free list */ da_set_check (d, prev, -next); da_set_base (d, next, -prev); }
static Bool da_extend_pool (DArray *d, TrieIndex to_index) { TrieIndex new_begin; TrieIndex i; TrieIndex free_tail; if (to_index <= 0 || TRIE_INDEX_MAX <= to_index) return FALSE; if (to_index < d->num_cells) return TRUE; d->cells = (DACell *) realloc (d->cells, (to_index + 1) * sizeof (DACell)); new_begin = d->num_cells; d->num_cells = to_index + 1; /* initialize new free list */ for (i = new_begin; i < to_index; i++) { da_set_check (d, i, -(i + 1)); da_set_base (d, i + 1, -i); } /* merge the new circular list to the old */ free_tail = -da_get_base (d, da_get_free_list (d)); da_set_check (d, free_tail, -new_begin); da_set_base (d, new_begin, -free_tail); da_set_check (d, to_index, -da_get_free_list (d)); da_set_base (d, da_get_free_list (d), -to_index); /* update header cell */ d->cells[0].check = d->num_cells; return TRUE; }
/** * @brief Delete an entry from trie * * @param trie : the trie * @param key : the key for the entry to delete * * @return boolean value indicating whether the key exists and is removed * * Delete an entry for the given @a key from @a trie. */ int trie_delete(trie_t trie, const char *key) { trie_idx_t s, t; short int suffix_idx; const char *p; /* walk through branches */ s = da_get_root(trie->da); for (p = key; !trie_da_separate_p(trie->da, s); p++) { if (da_walk(trie->da, &s, alpha_map_char_to_trie(*p)) < 0) { return -1; } if (*p == 0) { break; } } /* walk through tail */ t = trie_da_get_tail_index(trie->da, s); suffix_idx = 0; for ( ; ; p++) { if (tail_walk_char( trie->tail, t, &suffix_idx, alpha_map_char_to_trie(*p)) < 0) { return -1; } if (*p == 0) { break; } } tail_delete(trie->tail, t); da_set_base(trie->da, s, TRIE_INDEX_ERROR); da_prune(trie->da, s); trie->dirtyp = 1; return 0; }
/** * @brief Delete an entry from trie * * @param trie : the trie * @param key : the key for the entry to delete * * @return boolean value indicating whether the key exists and is removed * * Delete an entry for the given @a key from @a trie. */ Bool trie_delete (Trie *trie, const AlphaChar *key) { TrieIndex s, t; short suffix_idx; const AlphaChar *p; /* walk through branches */ s = da_get_root (trie->da); for (p = key; !trie_da_is_separate (trie->da, s); p++) { if (!da_walk (trie->da, &s, alpha_map_char_to_trie (trie->alpha_map, *p))) { return FALSE; } if (0 == *p) break; } /* walk through tail */ t = trie_da_get_tail_index (trie->da, s); suffix_idx = 0; for ( ; ; p++) { if (!tail_walk_char (trie->tail, t, &suffix_idx, alpha_map_char_to_trie (trie->alpha_map, *p))) { return FALSE; } if (0 == *p) break; } tail_delete (trie->tail, t); da_set_base (trie->da, s, TRIE_INDEX_ERROR); da_prune (trie->da, s); trie->is_dirty = TRUE; return TRUE; }
static inline void trie_da_set_tail_index(darray_t da, trie_idx_t s, trie_idx_t v) { da_set_base(da, s, -v); return; }