/* initialize root node */ static void hattrie_initroot(hattrie_t *T) { node_ptr node; if (T->bsize > 0) { node.b = hhash_create(TRIE_BUCKET_SIZE); node.b->flag = NODE_TYPE_HYBRID_BUCKET; node.b->c0 = 0x00; node.b->c1 = TRIE_MAXCHAR; T->root.t = alloc_trie_node(T, node); } else { T->root.t = alloc_empty_node(T); } }
value_t* hattrie_get(hattrie_t* T, const char* key, size_t len) { node_ptr parent = T->root; assert(*parent.flag & NODE_TYPE_TRIE); if (len == 0) return &parent.t->val; /* consume all trie nodes, now parent must be trie and child anything */ node_ptr node = hattrie_consume(&parent, &key, &len, 0); assert(*parent.flag & NODE_TYPE_TRIE); /* key wasn't consumed and using pure tries */ if (T->bsize == 0) { node.t = parent.t; while (len > 0) { node.t->xs[(unsigned char) *key].t = alloc_empty_node(T); node = node.t->xs[(unsigned char) *key]; ++key; --len; } return hattrie_useval(T, node); } /* if the key has been consumed on a trie node, use its value */ if (len == 0) { if (*node.flag & NODE_TYPE_TRIE) { return hattrie_useval(T, node); } else if (*node.flag & NODE_TYPE_HYBRID_BUCKET) { return hattrie_useval(T, parent); } } /* preemptively split the bucket if it is full */ while (ahtable_size(node.b) >= T->bsize) { hattrie_split(T, parent, node); /* after the split, the node pointer is invalidated, so we search from * the parent again. */ node = hattrie_consume(&parent, &key, &len, 0); /* if the key has been consumed on a trie node, use its value */ if (len == 0) { if (*node.flag & NODE_TYPE_TRIE) { return hattrie_useval(T, node); } else if (*node.flag & NODE_TYPE_HYBRID_BUCKET) { return hattrie_useval(T, parent); } } } assert(*node.flag & NODE_TYPE_PURE_BUCKET || *node.flag & NODE_TYPE_HYBRID_BUCKET); assert(len > 0); size_t m_old = node.b->m; value_t* val; if (*node.flag & NODE_TYPE_PURE_BUCKET) { val = ahtable_get(node.b, key + 1, len - 1); } else { val = ahtable_get(node.b, key, len); } T->m += (node.b->m - m_old); return val; }