/* * Copyright 2013 (c) Anna Schumaker. */ #include #include static GHashTable *filter_index = NULL; void __filter_copy(const struct set *lhs, struct set *rhs) { GHashTableIter iter; gpointer data; g_hash_table_iter_init(&iter, lhs->s_set); while (g_hash_table_iter_next(&iter, &data, NULL)) set_insert(rhs, GPOINTER_TO_UINT(data)); } void __filter_inline_intersect(const struct set *lhs, struct set *rhs) { GHashTableIter iter; gpointer data; g_hash_table_iter_init(&iter, rhs->s_set); while (g_hash_table_iter_next(&iter, &data, NULL)) { if (!set_has(lhs, GPOINTER_TO_UINT(data))) g_hash_table_iter_remove(&iter); } } void filter_init() { filter_index = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, set_free); } void filter_deinit() { g_hash_table_destroy(filter_index); } void filter_add(const gchar *text, void *data) { const gchar *c = g_utf8_next_char(text); glong begin, end; struct set *set; gchar *substr; for (begin = 0, end = 1; end <= g_utf8_strlen(text, -1); end++) { substr = g_utf8_substring(text, begin, end); set = g_hash_table_lookup(filter_index, substr); if (!set) { set = set_alloc(); g_hash_table_insert(filter_index, substr, set); } set_insert(set, GPOINTER_TO_UINT(data)); if (g_unichar_isspace(g_utf8_get_char(c))) { c = g_utf8_next_char(c); begin = ++end; } c = g_utf8_next_char(c); } } void filter_remove(const gchar *text, void *data) { const gchar *c = g_utf8_next_char(text); glong begin, end; struct set *set; gchar *substr; for (begin = 0, end = 1; end <= g_utf8_strlen(text, -1); end++) { substr = g_utf8_substring(text, begin, end); set = g_hash_table_lookup(filter_index, substr); if (set) set_remove(set, GPOINTER_TO_UINT(data)); if (g_unichar_isspace(g_utf8_get_char(c))) { c = g_utf8_next_char(c); begin = ++end; } c = g_utf8_next_char(c); } } void filter_search(const gchar *text, struct set *res) { gchar *lower = string_lowercase(text); struct set *found; glong begin, end; gchar *c, *substr; set_clear(res); c = lower; for (begin = 0, end = 1; end <= g_utf8_strlen(lower, -1); end++) { c = g_utf8_next_char(c); if ((*c != '\0') && !g_unichar_isspace(g_utf8_get_char(c))) continue; substr = g_utf8_substring(lower, begin, end); found = g_hash_table_lookup(filter_index, substr); g_free(substr); if (!found) { set_clear(res); break; } if (begin == 0) __filter_copy(found, res); else __filter_inline_intersect(found, res); c = g_utf8_next_char(c); begin = ++end; } g_free(lower); }