ocarina/core/filter.c

135 lines
2.7 KiB
C

/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/filter.h>
#include <core/string.h>
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;
}