From 93fb40360df4353a1f1d4535c096bdef2a165e09 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Fri, 29 Apr 2016 11:10:48 -0400 Subject: [PATCH] core/filter: filter_search() returns a new GHashTable I think this is cleaner than having an upper layer allocate the results set manually. This also lets me return NULL in the case that there were no results. Signed-off-by: Anna Schumaker --- core/filter.c | 24 +++++++++++++++--------- gui/queue.c | 11 ++++++++--- include/core/filter.h | 2 +- tests/core/filter.c | 26 +++++++++++++++----------- tests/core/tags/track.c | 30 ++++++++++++++++-------------- tests/gui/queue.c | 4 +++- 6 files changed, 58 insertions(+), 39 deletions(-) diff --git a/core/filter.c b/core/filter.c index 4533a612..813b2173 100644 --- a/core/filter.c +++ b/core/filter.c @@ -7,14 +7,19 @@ static GHashTable *filter_index = NULL; -void __filter_copy(GHashTable *lhs, GHashTable *rhs) +GHashTable *__filter_copy(GHashTable *set) { GHashTableIter iter; + GHashTable *res; gpointer data; - g_hash_table_iter_init(&iter, lhs); + 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(rhs, data); + g_hash_table_add(res, data); + + return res; } void __filter_inline_intersect(GHashTable *lhs, GHashTable *rhs) @@ -91,14 +96,13 @@ void filter_remove(const gchar *text, void *data) } } -void filter_search(const gchar *text, GHashTable *res) +GHashTable *filter_search(const gchar *text) { gchar *lower = string_lowercase(text); - GHashTable *found; + GHashTable *found, *res = NULL; glong begin, end; gchar *c, *substr; - g_hash_table_remove_all(res); c = lower; for (begin = 0, end = 1; end <= g_utf8_strlen(lower, -1); end++) { @@ -111,12 +115,13 @@ void filter_search(const gchar *text, GHashTable *res) g_free(substr); if (!found) { - g_hash_table_remove_all(res); + g_hash_table_destroy(res); + res = NULL; break; } - if (begin == 0) - __filter_copy(found, res); + if (!res) + res = __filter_copy(found); else __filter_inline_intersect(found, res); @@ -125,4 +130,5 @@ void filter_search(const gchar *text, GHashTable *res) } g_free(lower); + return res; } diff --git a/gui/queue.c b/gui/queue.c index ae4283b3..f53f79c5 100644 --- a/gui/queue.c +++ b/gui/queue.c @@ -68,6 +68,8 @@ static gboolean __queue_visible_func(GtkTreeModel *model, GtkTreeIter *iter, if (!gq_queue || (strlen(gtk_entry_get_text(GTK_ENTRY(data))) == 0)) return TRUE; + if (!gq_queue->gq_visible) + return FALSE; track = gui_queue_model_iter_get_track(gq_queue->gq_model, iter); return g_hash_table_contains(gq_queue->gq_visible, track); @@ -80,9 +82,13 @@ void __queue_filter(GtkSearchEntry *entry, gpointer data) if (!gq_queue) return; if (strlen(text) > 0) - filter_search(text, gq_queue->gq_visible); + gq_queue->gq_visible = filter_search(text); + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(gq_queue->gq_filter)); gui_view_scroll(); + + if (gq_queue->gq_visible) + g_hash_table_destroy(gq_queue->gq_visible); } struct gui_queue *gui_queue_alloc(struct queue *queue, const gchar *text, @@ -97,7 +103,7 @@ struct gui_queue *gui_queue_alloc(struct queue *queue, const gchar *text, GTK_TREE_MODEL(gq->gq_model), NULL); gq->gq_queue = queue; - gq->gq_visible = g_hash_table_new(g_direct_hash, g_direct_equal); + gq->gq_visible = NULL; gtk_tree_model_filter_set_visible_func( GTK_TREE_MODEL_FILTER(gq->gq_filter), __queue_visible_func, @@ -110,7 +116,6 @@ void gui_queue_free(struct queue *queue) { struct gui_queue *gq = gui_queue(queue); - g_hash_table_destroy(gq->gq_visible); queue->q_private = NULL; if (gq_queue == gq) diff --git a/include/core/filter.h b/include/core/filter.h index 21dff302..8ccd9abe 100644 --- a/include/core/filter.h +++ b/include/core/filter.h @@ -21,6 +21,6 @@ void filter_add(const gchar *, void *); void filter_remove(const gchar *, void *); /* Search for the input string in the index. */ -void filter_search(const gchar *, GHashTable *); +GHashTable *filter_search(const gchar *); #endif /* OCARINA_CORE_FILTER_H */ diff --git a/tests/core/filter.c b/tests/core/filter.c index b69444ac..524519ef 100644 --- a/tests/core/filter.c +++ b/tests/core/filter.c @@ -25,7 +25,7 @@ const gchar *test_strings[] = { static void test_filter() { - GHashTable *res = g_hash_table_new(g_direct_hash, g_direct_equal); + GHashTable *res; unsigned int i; filter_init(); @@ -34,46 +34,50 @@ static void test_filter() } test_loop_passed(); /* Search for a word! */ - filter_search("hyrule", res); + res = filter_search("hyrule"); test_equal(g_hash_table_size(res), 3); test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(1)), true); /* hyrule symphony */ test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */ test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(4)), true); /* hyrule castle */ + g_hash_table_destroy(res); /* A second search should clear the set. */ - filter_search("zelda", res); + res = filter_search("zelda"); test_equal(g_hash_table_size(res), 2); test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(11)), true); /* princess zelda */ test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(13)), true); /* the legend of zelda medley */ + g_hash_table_destroy(res); /* Partial word search. */ - filter_search("ko", res); + res = filter_search("ko"); test_equal(g_hash_table_size(res), 2); test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(0)), true); /* koji kondo */ test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(2)), true); /* kokiri forest */ + g_hash_table_destroy(res); /* Multiple word search. */ - filter_search("hyrule field", res); + res = filter_search("hyrule field"); test_equal(g_hash_table_size(res), 1); test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */ + g_hash_table_destroy(res); /* Search for unknown word. */ - filter_search("field termina", res); - test_equal(g_hash_table_size(res), 0); + res = filter_search("field termina"); + test_equal((void *)res, NULL); /* Search for empty string. */ - filter_search("", res); - test_equal(g_hash_table_size(res), 0); + res = filter_search(""); + test_equal((void *)res, NULL); /* Remove a string and search again. */ filter_remove("hyrule symphony", GUINT_TO_POINTER(1)); - filter_search("hyrule", res); + res = filter_search("hyrule"); test_equal(g_hash_table_size(res), 2); test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(3)), true); /* hyrule field */ test_equal(g_hash_table_contains(res, GUINT_TO_POINTER(4)), true); /* hyrule castle */ + g_hash_table_destroy(res); filter_deinit(); - g_hash_table_destroy(res); } DECLARE_UNIT_TESTS( diff --git a/tests/core/tags/track.c b/tests/core/tags/track.c index 2c0f2c56..e2edbcdc 100644 --- a/tests/core/tags/track.c +++ b/tests/core/tags/track.c @@ -126,29 +126,31 @@ static void test_track() static void test_track_filter() { const struct db_ops *track_ops = test_track_ops(); - GHashTable *search = g_hash_table_new(g_direct_hash, g_direct_equal); struct track *track; + GHashTable *search; track = test_alloc("0/Hyrule Symphony/01 - Title Theme.ogg"); track->tr_dbe.dbe_index = 0; track_ops->dbe_setup(&track->tr_dbe); - filter_search("Title Theme", search); + search = filter_search("Title Theme"); test_equal(g_hash_table_size(search), 1); test_equal(g_hash_table_contains(search, track), true); - - filter_search("Koji Kondo", search); - test_equal(g_hash_table_size(search), 1); - test_equal(g_hash_table_contains(search, track), true); - - filter_search("Hyrule Symphony", search); - test_equal(g_hash_table_size(search), 1); - test_equal(g_hash_table_contains(search, track), true); - - filter_search("No Track", search); - test_equal(g_hash_table_size(search), 0); - g_hash_table_destroy(search); + + search = filter_search("Koji Kondo"); + test_equal(g_hash_table_size(search), 1); + test_equal(g_hash_table_contains(search, track), true); + g_hash_table_destroy(search); + + search = filter_search("Hyrule Symphony"); + test_equal(g_hash_table_size(search), 1); + test_equal(g_hash_table_contains(search, track), true); + g_hash_table_destroy(search); + + search = filter_search("No Track"); + test_equal((void *)search, NULL); + g_free(track->tr_path); track_ops->dbe_free(&track->tr_dbe); } diff --git a/tests/gui/queue.c b/tests/gui/queue.c index aec69988..a843d48f 100644 --- a/tests/gui/queue.c +++ b/tests/gui/queue.c @@ -50,7 +50,10 @@ static void test_queue() gtk_init(&argc, NULL); gui_builder_init("share/ocarina/ocarina6.glade"); + queue_init(&q, 0, &test_ops); gui_view_init(); + while (idle_run_task()) {}; + search = GTK_ENTRY(gui_builder_widget("o_search")); enable = GTK_SWITCH(gui_builder_widget("o_enable")); random = GTK_TOGGLE_BUTTON(gui_builder_widget("o_random")); @@ -60,7 +63,6 @@ static void test_queue() treeview = GTK_TREE_VIEW(gui_builder_widget("o_treeview")); /* Test initialization */ - queue_init(&q, 0, &test_ops); gq = gui_queue(&q); test_equal((void *)gq->gq_queue, (void *)&q); test_not_equal((void *)gq->gq_model, NULL);