[glib/wip/nielsdg/g-list-store-find: 43/43] gliststore: Add item lookup functions
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/nielsdg/g-list-store-find: 43/43] gliststore: Add item lookup functions
- Date: Fri, 20 Sep 2019 13:42:51 +0000 (UTC)
commit d8687278a640a31fb78f3143918197f2e2003732
Author: Niels De Graef <nielsdegraef gmail com>
Date: Sun Sep 8 15:42:57 2019 +0200
gliststore: Add item lookup functions
Currently, there is no quick way to find whether and element is already
part of a list store, except for manually writing a for-loop and calling
`g_list_model_get_item()` and breaking when you find the item.
This is mostly just a small API addition to support this use case.
Fixes https://gitlab.gnome.org/GNOME/glib/issues/1011
gio/gliststore.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
gio/gliststore.h | 11 +++++++
gio/tests/glistmodel.c | 67 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 161 insertions(+)
---
diff --git a/gio/gliststore.c b/gio/gliststore.c
index 7b2a453d6..864b60df5 100644
--- a/gio/gliststore.c
+++ b/gio/gliststore.c
@@ -494,3 +494,86 @@ g_list_store_splice (GListStore *store,
g_list_store_items_changed (store, position, n_removals, n_additions);
}
+
+/**
+ * g_list_store_find_with_equal_func:
+ * @store: a #GListStore
+ * @item: (type GObject): an item
+ * @equal_func: (scope call): A custom equality check function
+ * @position: (out) (optional): the first position of @item, if it was found.
+ *
+ * Looks up the given @item in the list store by looping over the items and
+ * comparing them with @compare_func until the first occurrence of @item which
+ * matches. If @item was not found, then @position will not be set, and this
+ * method will return %FALSE.
+ *
+ * Returns: Whether @store contains @item. If it was found, @first_position
+ * will be set to the position where @item occurred for the first time.
+ *
+ * Since: 2.62
+ */
+gboolean
+g_list_store_find_with_equal_func (GListStore *store,
+ gpointer item,
+ GEqualFunc equal_func,
+ guint *position)
+{
+ GSequenceIter *iter, *begin, *end;
+
+ g_return_val_if_fail (G_IS_LIST_STORE (store), FALSE);
+ g_return_val_if_fail (g_type_is_a (G_OBJECT_TYPE (item), store->item_type),
+ FALSE);
+ g_return_val_if_fail (equal_func != NULL, FALSE);
+
+ /* NOTE: We can't use g_sequence_lookup() or g_sequence_search(), because we
+ * can't assume the sequence is sorted. */
+ begin = g_sequence_get_begin_iter (store->items);
+ end = g_sequence_get_end_iter (store->items);
+
+ iter = begin;
+ while (iter != end)
+ {
+ gpointer iter_item;
+
+ iter_item = g_sequence_get (iter);
+ if (equal_func (iter_item, item))
+ {
+ if (position)
+ *position = g_sequence_iter_get_position (iter);
+ return TRUE;
+ }
+
+ iter = g_sequence_iter_next (iter);
+ }
+
+ return FALSE;
+}
+
+/**
+ * g_list_store_find:
+ * @store: a #GListStore
+ * @item: (type GObject): an item
+ * @position: (out) (optional): the first position of @item, if it was found.
+ *
+ * Looks up the given @item in the list store by looping over the items until
+ * the first occurrence of @item. If @item was not found, then @position will
+ * not be set, and this method will return %FALSE.
+ *
+ * If you need to compare the two items with a custom comparison function, use
+ * g_list_store_find_with_equal_func() with a custom #GEqualFunc instead.
+ *
+ * Returns: Whether @store contains @item. If it was found, @first_position
+ * will be set to the position where @item occurred for the first time.
+ *
+ * Since: 2.62
+ */
+gboolean
+g_list_store_find (GListStore *store,
+ gpointer item,
+ guint *position)
+{
+ return g_list_store_find_with_equal_func (store,
+ item,
+ g_direct_equal,
+ position);
+}
diff --git a/gio/gliststore.h b/gio/gliststore.h
index 407d542fb..ef3b83951 100644
--- a/gio/gliststore.h
+++ b/gio/gliststore.h
@@ -72,6 +72,17 @@ void g_list_store_splice (GListSt
gpointer *additions,
guint n_additions);
+GLIB_AVAILABLE_IN_2_64
+gboolean g_list_store_find (GListStore *store,
+ gpointer item,
+ guint *position);
+
+GLIB_AVAILABLE_IN_2_64
+gboolean g_list_store_find_with_equal_func (GListStore *store,
+ gpointer item,
+ GEqualFunc equal_func,
+ guint *position);
+
G_END_DECLS
#endif /* __G_LIST_STORE_H__ */
diff --git a/gio/tests/glistmodel.c b/gio/tests/glistmodel.c
index 562037f62..5ecf45f79 100644
--- a/gio/tests/glistmodel.c
+++ b/gio/tests/glistmodel.c
@@ -805,6 +805,72 @@ test_store_past_end (void)
g_object_unref (store);
}
+static gboolean
+list_model_casecmp_action_by_name (gconstpointer a,
+ gconstpointer b)
+{
+ return g_ascii_strcasecmp (g_action_get_name (G_ACTION (a)),
+ g_action_get_name (G_ACTION (b))) == 0;
+}
+
+/* Test if find() and find_with_equal_func() works */
+static void
+test_store_find (void)
+{
+ GListStore *store;
+ guint position = 100;
+ const gchar *item_strs[4] = { "aaa", "bbb", "xxx", "ccc" };
+ GSimpleAction *items[4] = { NULL, };
+ GSimpleAction *other_item;
+ guint i;
+
+ store = g_list_store_new (G_TYPE_SIMPLE_ACTION);
+
+ for (i = 0; i < G_N_ELEMENTS (item_strs); i++)
+ items[i] = g_simple_action_new (item_strs[i], NULL);
+
+ /* Shouldn't crash on an empty list, or change the position pointer */
+ g_assert_false (g_list_store_find (store, items[0], NULL));
+ g_assert_false (g_list_store_find (store, items[0], &position));
+ g_assert_cmpint (position, ==, 100);
+
+ for (i = 0; i < G_N_ELEMENTS (item_strs); i++)
+ g_list_store_append (store, items[i]);
+
+ /* Check whether it could still find the the elements */
+ for (i = 0; i < G_N_ELEMENTS (item_strs); i++)
+ {
+ g_assert_true (g_list_store_find (store, items[i], &position));
+ g_assert_cmpint (position, ==, i);
+ /* Shouldn't try to write to position pointer if NULL given */
+ g_assert_true (g_list_store_find (store, items[i], NULL));
+ }
+
+ /* try to find element not part of the list */
+ other_item = g_simple_action_new ("111", NULL);
+ g_assert_false (g_list_store_find (store, other_item, NULL));
+ g_clear_object (&other_item);
+
+ /* Re-add item; find() should only return the first position */
+ g_list_store_append (store, items[0]);
+ g_assert_true (g_list_store_find (store, items[0], &position));
+ g_assert_cmpint (position, ==, 0);
+
+ /* try to find element which should only work with custom equality check */
+ other_item = g_simple_action_new ("XXX", NULL);
+ g_assert_false (g_list_store_find (store, other_item, NULL));
+ g_assert_true (g_list_store_find_with_equal_func (store,
+ other_item,
+ list_model_casecmp_action_by_name,
+ &position));
+ g_assert_cmpint (position, ==, 2);
+ g_clear_object (&other_item);
+
+ for (i = 0; i < G_N_ELEMENTS (item_strs); i++)
+ g_clear_object(&items[i]);
+ g_clear_object (&store);
+}
+
int main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
@@ -837,6 +903,7 @@ int main (int argc, char *argv[])
g_test_add_func ("/glistmodel/store/items-changed",
test_store_signal_items_changed);
g_test_add_func ("/glistmodel/store/past-end", test_store_past_end);
+ g_test_add_func ("/glistmodel/store/find", test_store_find);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]