/* * Copyright 2013 (c) Anna Schumaker. */ #include #include static GHashTable *filter_index = NULL; GHashTable *__filter_copy(GHashTable *set) { GHashTableIter iter; GHashTable *res; gpointer data; res = g_hash_table_new(g_direct_hash, g_direct_equal); g_hash_table_iter_init(&iter, set); while (g_hash_table_iter_next(&iter, &data, NULL)) g_hash_table_add(res, data); return res; } void __filter_inline_intersect(GHashTable *lhs, GHashTable *rhs) { GHashTableIter iter; gpointer data; g_hash_table_iter_init(&iter, rhs); while (g_hash_table_iter_next(&iter, &data, NULL)) { if (!g_hash_table_contains(lhs, 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, (GDestroyNotify)g_hash_table_destroy); } 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; GHashTable *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 = g_hash_table_new(g_direct_hash, g_direct_equal); g_hash_table_insert(filter_index, substr, set); } g_hash_table_add(set, 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; GHashTable *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) g_hash_table_remove(set, data); if (g_unichar_isspace(g_utf8_get_char(c))) { c = g_utf8_next_char(c); begin = ++end; } c = g_utf8_next_char(c); } } GHashTable *filter_search(const gchar *text) { gchar *lower = string_lowercase(text); GHashTable *found, *res = NULL; glong begin, end; gchar *c, *substr; 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) { g_hash_table_destroy(res); res = NULL; break; } if (!res) res = __filter_copy(found); else __filter_inline_intersect(found, res); c = g_utf8_next_char(c); begin = ++end; } g_free(lower); return res; }