core/event-list: Use gdkarrayimpl.c as backing store
GSequence is useful and provides us with a convenient API, however, it pretty much guarantees cache misses when iterating, lots of pointer chasing, and scattered memory. gdkarrayimpl.c works around all of that, at the cost of more expensive additions and removals. But because we do a lot more lookups compared to edits, there should still be benefits to it. Change the backing store to be based on gdkarrayimpl.c. Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/757>
This commit is contained in:
+55
-87
@@ -26,19 +26,19 @@
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#define GDK_ARRAY_TYPE_NAME GcalEventArray
|
||||
#define GDK_ARRAY_NAME gcal_event_array
|
||||
#define GDK_ARRAY_ELEMENT_TYPE GcalEvent*
|
||||
#define GDK_ARRAY_PREALLOC 50
|
||||
#define GDK_ARRAY_FREE_FUNC g_object_unref
|
||||
#include "gdkarrayimpl.c"
|
||||
|
||||
struct _GcalEventList
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GSequence *events;
|
||||
GHashTable *event_to_iter;
|
||||
GHashTable *uid_to_iter;
|
||||
guint n_events;
|
||||
|
||||
/* cache */
|
||||
guint last_position;
|
||||
GSequenceIter *last_iter;
|
||||
gboolean last_position_valid;
|
||||
GcalEventArray event_array;
|
||||
GHashTable *events;
|
||||
};
|
||||
|
||||
static void g_list_model_interface_init (GListModelInterface *iface);
|
||||
@@ -47,28 +47,6 @@ G_DEFINE_FINAL_TYPE_WITH_CODE (GcalEventList, gcal_event_list, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, g_list_model_interface_init))
|
||||
|
||||
|
||||
/*
|
||||
* Auxiliary functions
|
||||
*/
|
||||
|
||||
static void
|
||||
gcal_event_list_items_changed (GcalEventList *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
{
|
||||
/* check if the iter cache may have been invalidated */
|
||||
if (position <= self->last_position)
|
||||
{
|
||||
self->last_iter = NULL;
|
||||
self->last_position = 0;
|
||||
self->last_position_valid = FALSE;
|
||||
}
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GListModel interface
|
||||
*/
|
||||
@@ -86,7 +64,7 @@ gcal_event_list_get_n_items (GListModel *model)
|
||||
|
||||
g_assert (GCAL_IS_EVENT_LIST (self));
|
||||
|
||||
return g_hash_table_size (self->event_to_iter);
|
||||
return gcal_event_array_get_size (&self->event_array);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
@@ -94,31 +72,13 @@ gcal_event_list_get_item (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
GcalEventList *self = (GcalEventList *) model;
|
||||
GSequenceIter *it = NULL;
|
||||
|
||||
g_assert (GCAL_IS_EVENT_LIST (self));
|
||||
|
||||
if (self->last_position_valid)
|
||||
{
|
||||
if (position < G_MAXUINT && self->last_position == position + 1)
|
||||
it = g_sequence_iter_prev (self->last_iter);
|
||||
else if (position > 0 && self->last_position == position - 1)
|
||||
it = g_sequence_iter_next (self->last_iter);
|
||||
else if (self->last_position == position)
|
||||
it = self->last_iter;
|
||||
}
|
||||
|
||||
if (it == NULL)
|
||||
it = g_sequence_get_iter_at_pos (self->events, position);
|
||||
|
||||
self->last_iter = it;
|
||||
self->last_position = position;
|
||||
self->last_position_valid = TRUE;
|
||||
|
||||
if (g_sequence_iter_is_end (it))
|
||||
return NULL;
|
||||
if (position < gcal_event_array_get_size (&self->event_array))
|
||||
return g_object_ref (gcal_event_array_get (&self->event_array, position));
|
||||
else
|
||||
return g_object_ref (g_sequence_get (it));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -139,8 +99,8 @@ gcal_event_list_finalize (GObject *object)
|
||||
{
|
||||
GcalEventList *self = (GcalEventList *)object;
|
||||
|
||||
g_clear_pointer (&self->event_to_iter, g_hash_table_destroy);
|
||||
g_clear_pointer (&self->events, g_sequence_free);
|
||||
gcal_event_array_clear (&self->event_array);
|
||||
g_clear_pointer (&self->events, g_hash_table_destroy);
|
||||
|
||||
G_OBJECT_CLASS (gcal_event_list_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -156,8 +116,8 @@ gcal_event_list_class_init (GcalEventListClass *klass)
|
||||
static void
|
||||
gcal_event_list_init (GcalEventList *self)
|
||||
{
|
||||
self->events = g_sequence_new (g_object_unref);
|
||||
self->event_to_iter = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
gcal_event_array_init (&self->event_array);
|
||||
self->events = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,23 +170,20 @@ gcal_event_list_add_events (GcalEventList *self,
|
||||
g_assert (GCAL_IS_EVENT_LIST (self));
|
||||
g_assert (events != NULL);
|
||||
|
||||
position = g_hash_table_size (self->event_to_iter);
|
||||
position = gcal_event_array_get_size (&self->event_array);
|
||||
|
||||
for (gsize i = 0; events[i]; i++)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
|
||||
if (g_hash_table_contains (self->event_to_iter, events[i]))
|
||||
if (g_hash_table_contains (self->events, events[i]))
|
||||
continue;
|
||||
|
||||
iter = g_sequence_append (self->events, g_object_ref (events[i]));
|
||||
|
||||
g_hash_table_insert (self->event_to_iter, events[i], iter);
|
||||
gcal_event_array_append (&self->event_array, g_object_ref (events[i]));
|
||||
g_hash_table_add (self->events, events[i]);
|
||||
n_added++;
|
||||
}
|
||||
|
||||
if (n_added > 0)
|
||||
gcal_event_list_items_changed (self, position, 0, n_added);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, n_added);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,35 +218,47 @@ void
|
||||
gcal_event_list_remove_events (GcalEventList *self,
|
||||
GcalEvent **events)
|
||||
{
|
||||
g_autoptr (GHashTable) contained_events = NULL;
|
||||
g_autoptr (GtkBitset) bitset = NULL;
|
||||
g_autoptr (GPtrArray) iters = NULL;
|
||||
GtkBitsetIter iter;
|
||||
|
||||
g_assert (GCAL_IS_EVENT_LIST (self));
|
||||
g_assert (events != NULL);
|
||||
|
||||
bitset = gtk_bitset_new_empty ();
|
||||
iters = g_ptr_array_new ();
|
||||
contained_events = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
for (gsize i = 0; events[i]; i++)
|
||||
for (size_t i = 0; events[i]; i++)
|
||||
{
|
||||
GSequenceIter *iter = g_hash_table_lookup (self->event_to_iter, events[i]);
|
||||
|
||||
if (!iter)
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (iters, iter);
|
||||
gtk_bitset_add (bitset, g_sequence_iter_get_position (iter));
|
||||
|
||||
g_hash_table_remove (self->event_to_iter, events[i]);
|
||||
if (g_hash_table_contains (self->events, events[i]))
|
||||
g_hash_table_add (contained_events, events[i]);
|
||||
}
|
||||
|
||||
for (gsize i = 0; i < iters->len; i++)
|
||||
for (size_t i = 0; i < gcal_event_array_get_size (&self->event_array); i++)
|
||||
{
|
||||
GSequenceIter *iter = g_ptr_array_index (iters, i);
|
||||
GcalEvent *event = gcal_event_array_get (&self->event_array, i);
|
||||
|
||||
g_assert (iter != NULL);
|
||||
if (g_hash_table_contains (contained_events, event))
|
||||
{
|
||||
g_hash_table_remove (contained_events, event);
|
||||
g_hash_table_remove (self->events, event);
|
||||
gtk_bitset_add (bitset, i);
|
||||
}
|
||||
|
||||
g_sequence_remove (iter);
|
||||
if (g_hash_table_size (contained_events) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
for (gtk_bitset_iter_init_last (&iter, bitset, NULL);
|
||||
gtk_bitset_iter_is_valid (&iter);
|
||||
gtk_bitset_iter_previous (&iter, NULL))
|
||||
{
|
||||
gcal_event_array_splice (&self->event_array,
|
||||
gtk_bitset_iter_get_value (&iter),
|
||||
1,
|
||||
FALSE,
|
||||
NULL,
|
||||
0);
|
||||
}
|
||||
|
||||
if (!gtk_bitset_is_empty (bitset))
|
||||
@@ -299,7 +268,7 @@ gcal_event_list_remove_events (GcalEventList *self,
|
||||
guint range_size = last - first + 1;
|
||||
guint n_removed = gtk_bitset_get_size_in_range (bitset, first, last);
|
||||
|
||||
gcal_event_list_items_changed (self, first, range_size, range_size - n_removed);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), first, range_size, range_size - n_removed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,12 +284,11 @@ gcal_event_list_remove_all_events (GcalEventList *self)
|
||||
|
||||
g_assert (GCAL_IS_EVENT_LIST (self));
|
||||
|
||||
n_removed = g_hash_table_size (self->event_to_iter);
|
||||
n_removed = gcal_event_array_get_size (&self->event_array);
|
||||
|
||||
g_hash_table_remove_all (self->event_to_iter);
|
||||
g_sequence_remove_range (g_sequence_get_begin_iter (self->events),
|
||||
g_sequence_get_end_iter (self->events));
|
||||
g_hash_table_remove_all (self->events);
|
||||
gcal_event_array_clear (&self->event_array);
|
||||
|
||||
if (n_removed > 0)
|
||||
gcal_event_list_items_changed (self, 0, n_removed, 0);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_removed, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user