static char *hyphen(char *dst, const char *src, char delim) { const char *exp = expchck(src, delim); if (exp) return strcpy(dst, exp); char txt[TOKLEN + 1]; sprintf(txt, ".%s.", src); char *txtend = txt + strlen(txt); uint8_t wght[TOKLEN + 1] = {0}; for (char *s = txt; *s; ++s) { char *p = s; trie_t trie = pattern; while (p <= txtend && trie) { if (trie_child(trie, 0)) for (char *i = s; i <= p; ++i) wght[i - txt] = MAX( wght[i - txt], ((uint8_t *)trie_find(trie, ""))[i - s] ); trie = trie_child(trie, tolower(*p++)); } } wght[1] = wght[2] = 0; wght[txtend - txt - 1] = wght[txtend - txt - 2] = 0; char *pdst = dst; for (char *s = txt + 1; s < txtend - 1; *pdst++ = *s++) if (wght[s - txt] & 1) *pdst++ = delim; *pdst = 0; return dst; }
static void falcon_cache_recursive_foreach_descendant(const trie_node_t *node, GFunc func, gpointer udata) { falcon_object_t *data = NULL; while (node) { if (trie_child(node)) falcon_cache_recursive_foreach_descendant(trie_child(node), func, udata); if ((data = trie_data(node))) func(data, udata); node = trie_next(node); } }
/* * Returns non-null if trie contains the specified word, otherwise * null. In fact, returns the very node of the trie that represents * the word, if it exists. 's' must be null terminated. */ Trie* trie_contains( Trie *t, unsigned char* s ) { unsigned char *prefix; do { prefix = t->prefix; while ( prefix[0] && s[0] && prefix[0] == s[0] ) { ++prefix; ++s; } if ( prefix[0] ) { // node's prefix is *longer* than the word we're checking, so // word is not contained in trie return NULL; } // if we've reached the end of our word, then this node must also // represent the end of a trie member, if the word is contained in // the trie unsigned char c = s[0]; if ( c == 0 ) { if ( t->is_end_of_string ) { return t; } else { return NULL; } } t = trie_child( t, c, NULL ); if ( !t ) { return NULL; } } while ( 1 ); }
static void recursive_print(const trie_node_t *node, guint l) { guint i = 0; guint len = 0; while (node) { printf("%s", trie_key(node) ? trie_key(node) : "ROOT"); if (trie_child(node)) { if (trie_key(node)) len = strlen(trie_key(node)) + 2; printf("->"); recursive_print(trie_child(node), l + len); } if (trie_next(node)) printf("\n"); for (i = 0; i < l; i++) printf(" "); node = trie_next(node); } }
void falcon_cache_foreach_top(falcon_cache_t *cache, GFunc func, gpointer userdata) { g_return_if_fail(cache); g_return_if_fail(func); g_mutex_lock(cache->lock); falcon_cache_recursive_foreach_top(trie_child(cache->objects), func, userdata); g_mutex_unlock(cache->lock); }
void falcon_cache_foreach_descendant(falcon_cache_t *cache, const gchar *name, GFunc func, gpointer userdata) { trie_node_t *node = NULL; falcon_object_t *data = NULL; g_return_if_fail(cache); g_return_if_fail(func); g_mutex_lock(cache->lock); node = trie_find(cache->objects, name); falcon_cache_recursive_foreach_descendant(trie_child(node), func, userdata); if ((data = trie_data(node))) func(data, userdata); g_mutex_unlock(cache->lock); }
void falcon_cache_foreach_child(falcon_cache_t *cache, const gchar *name, GFunc func, gpointer userdata) { trie_node_t *node = NULL; trie_node_t *next = NULL; falcon_object_t *data = NULL; g_return_if_fail(cache); g_return_if_fail(func); g_mutex_lock(cache->lock); node = trie_find(cache->objects, name); next = trie_child(node); while (next) { if ((data = trie_data(next))) func(data, userdata); next = trie_next(next); } if ((data = trie_data(node))) func(data, userdata); g_mutex_unlock(cache->lock); }
/* Add a word (and an optional associated data) to the trie. 's', the * word, will be duplicated, so the trie does assume memory * "ownership" of this string. If 'data' is not null, be sure to * write and specify a callback function for the 'free_data_callback' * argument of trie_free(), so that this "user" data is freed. If * word already exists in the trie, this function returns 0 and the * trie will not be modified. * */ int trie_add( Trie *t, unsigned char* s, void *data ) { Trie *last = t; unsigned char prefix[MAX_WORD_LEN + 1]; prefix[0] = 0; // check validity of word before (potentially) making any changes to // the trie, which might otherwise leave it with a partially-added // path (because an invalid char is found later in the word) if ( !_is_valid_word( s ) ) { return 0; } // (we could make this duplication check while we add, but this is // more readable) if ( trie_contains( t, s ) ) { return 0; } do { if ( *s == 0 || t == NULL ) { if ( t == NULL ) { // it's now time to allocate our new child node t = trie_new_child( last, s ); } t->is_end_of_string = 1; t->data = data; return 1; } else { last = t; Trie *child = trie_child( t, s[0], prefix ); if ( !child ) { // cause logic, above, to create a new child t = NULL; } else { int n = 0; while ( prefix[n] && s[n] && prefix[n] == s[n] ) { ++n; } // if 's' is a prefix of child->prefix, or if 's' differs from // prefix at some point, then we must split the folded-path // child into two nodes if ( prefix[n] != 0 ) { // insert new intermediate node, breaking up a folded path int old_child_index = _char_to_index( child->prefix[0] ); // set the child's prefix to the tail of the original prefix memmove( child->prefix, child->prefix + n, strlen( child->prefix + n ) + 1 ); // orphan the child (for later re-parenting) t->children[old_child_index] = NULL; // insert the new intermediate child, assigning it the head // of the original prefix; 't' will now represent the new, // intermediate child prefix[n] = 0; t = trie_new_child( t, prefix ); // make the new intermediate child the parent of the // original child _trie_alloc_children_array( t ); t->children[_char_to_index( child->prefix[0] )] = child; // we now resume the normal loop logic, which will finish up // the initialization of our new intermediate child and then // return... } else { t = child; } s += n; } } } while ( 1 ); return 1; }