[libshumate] map-layer: Use hash table instead of pointer array
- From: Corentin Noël <corentinnoel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libshumate] map-layer: Use hash table instead of pointer array
- Date: Tue, 6 Jul 2021 09:51:41 +0000 (UTC)
commit 2a33b579ea79881cb4f6fc3c94b734f3e1807f05
Author: James Westman <james jwestman net>
Date: Tue Jun 22 22:45:12 2021 -0500
map-layer: Use hash table instead of pointer array
Store the tiles in a hash table rather than a pointer array. This is a
more suitable data structure since we often look up tiles by their grid
position, and hash tables can still be easily iterated.
shumate/shumate-map-layer.c | 142 +++++++++++++++++++++++++++-----------------
1 file changed, 89 insertions(+), 53 deletions(-)
---
diff --git a/shumate/shumate-map-layer.c b/shumate/shumate-map-layer.c
index 7cdabb1..c580d47 100644
--- a/shumate/shumate-map-layer.c
+++ b/shumate/shumate-map-layer.c
@@ -27,7 +27,7 @@ struct _ShumateMapLayer
ShumateMapSource *map_source;
- GPtrArray *tiles_positions;
+ GHashTable *tile_children;
guint required_tiles_rows;
guint required_tiles_columns;
GHashTable *tile_fill;
@@ -49,30 +49,50 @@ static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
typedef struct
{
- ShumateTile *tile;
guint left_attach;
guint top_attach;
} TileGridPosition;
-static TileGridPosition *
-tile_grid_position_new (ShumateTile *tile,
- guint left_attach,
- guint top_attach)
+static void
+tile_grid_position_init (TileGridPosition *self,
+ guint left_attach,
+ guint top_attach)
{
- TileGridPosition *self = g_new0 (TileGridPosition, 1);
- self->tile = g_object_ref (tile);
self->left_attach = left_attach;
self->top_attach = top_attach;
+}
+
+static TileGridPosition *
+tile_grid_position_new (guint left_attach,
+ guint top_attach)
+{
+ TileGridPosition *self = g_new0 (TileGridPosition, 1);
+ tile_grid_position_init (self, left_attach, top_attach);
return self;
}
+static guint
+tile_grid_position_hash (gconstpointer pointer)
+{
+ const TileGridPosition *self = pointer;
+ return self->left_attach ^ self->top_attach;
+}
+
+static gboolean
+tile_grid_position_equal (gconstpointer a, gconstpointer b)
+{
+ const TileGridPosition *pos_a = a;
+ const TileGridPosition *pos_b = b;
+ return pos_a->left_attach == pos_b->left_attach && pos_a->top_attach == pos_b->top_attach;
+}
+
static void
-tile_grid_position_free (TileGridPosition *self)
+tile_grid_position_free (gpointer pointer)
{
+ TileGridPosition *self = pointer;
if (!self)
return;
- g_clear_object (&self->tile);
self->left_attach = 0;
self->top_attach = 0;
g_free (self);
@@ -80,19 +100,14 @@ tile_grid_position_free (TileGridPosition *self)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (TileGridPosition, tile_grid_position_free);
-static TileGridPosition *
+static ShumateTile *
shumate_map_layer_get_tile_child (ShumateMapLayer *self,
guint left_attach,
guint top_attach)
{
- for (guint index = 0; index < self->tiles_positions->len; index++)
- {
- TileGridPosition *tile_child = g_ptr_array_index (self->tiles_positions, index);
- if (tile_child->left_attach == left_attach && tile_child->top_attach == top_attach)
- return tile_child;
- }
-
- return NULL;
+ TileGridPosition pos;
+ tile_grid_position_init (&pos, left_attach, top_attach);
+ return g_hash_table_lookup (self->tile_children, &pos);
}
static inline int
@@ -118,7 +133,7 @@ maybe_shift_grid (ShumateMapLayer *self,
int new_first_tile_column,
int new_first_tile_row)
{
- TileGridPosition *first_tile;
+ ShumateTile *first_tile;
int first_tile_column;
int first_tile_row;
int column_backward_diff;
@@ -127,13 +142,16 @@ maybe_shift_grid (ShumateMapLayer *self,
int row_forward_diff;
int column_diff;
int row_diff;
+ GHashTableIter iter;
+ gpointer key, value;
+ GHashTable *new_tile_children;
first_tile = shumate_map_layer_get_tile_child (self, 0, 0);
if (!first_tile)
return;
- first_tile_column = shumate_tile_get_x (first_tile->tile);
- first_tile_row = shumate_tile_get_y (first_tile->tile);
+ first_tile_column = shumate_tile_get_x (first_tile);
+ first_tile_row = shumate_tile_get_y (first_tile);
/* The allocation function uses unsigned ints everywhere, and they do wrap
* around, so we can often receive super large values here.
@@ -166,18 +184,29 @@ maybe_shift_grid (ShumateMapLayer *self,
if (ABS (column_diff) >= self->required_tiles_columns || ABS (row_diff) >= self->required_tiles_rows)
return;
- for (gsize i = 0; i < self->tiles_positions->len; i++)
+ new_tile_children = g_hash_table_new_full (tile_grid_position_hash, tile_grid_position_equal,
tile_grid_position_free, g_object_unref);
+ g_hash_table_iter_init (&iter, self->tile_children);
+
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- TileGridPosition *tile_child = g_ptr_array_index (self->tiles_positions, i);
+ TileGridPosition *pos = key;
+ ShumateTile *tile = value;
+
+ g_hash_table_iter_steal (&iter);
- tile_child->left_attach = modadd (tile_child->left_attach,
- -column_diff,
- self->required_tiles_columns);
+ pos->left_attach = modadd (pos->left_attach,
+ -column_diff,
+ self->required_tiles_columns);
- tile_child->top_attach = modadd (tile_child->top_attach,
- -row_diff,
- self->required_tiles_rows);
+ pos->top_attach = modadd (pos->top_attach,
+ -row_diff,
+ self->required_tiles_rows);
+
+ g_hash_table_insert (new_tile_children, pos, tile);
}
+
+ g_clear_pointer (&self->tile_children, g_hash_table_unref);
+ self->tile_children = new_tile_children;
}
static void
@@ -203,13 +232,13 @@ recompute_grid (ShumateMapLayer *self,
for (guint row = 0; row < self->required_tiles_rows; row++)
{
ShumateTile *tile;
- TileGridPosition *tile_child;
+ TileGridPosition *pos;
tile = shumate_tile_new ();
shumate_tile_set_size (tile, tile_size);
gtk_widget_insert_before (GTK_WIDGET (tile), widget, NULL);
- tile_child = tile_grid_position_new (tile, column, row);
- g_ptr_array_add (self->tiles_positions, tile_child);
+ pos = tile_grid_position_new (column, row);
+ g_hash_table_insert (self->tile_children, pos, g_object_ref (tile));
}
}
}
@@ -221,15 +250,20 @@ recompute_grid (ShumateMapLayer *self,
{
for (guint row = 0; row < self->required_tiles_rows; row++)
{
- TileGridPosition *tile_child = shumate_map_layer_get_tile_child (self, column, row);
- if (!tile_child)
+ TileGridPosition pos;
+ ShumateTile *tile;
+
+ tile_grid_position_init (&pos, column, row);
+ tile = g_hash_table_lookup (self->tile_children, &pos);
+
+ if (!tile)
{
g_critical ("Unable to find tile to remove at (%u;%u)", column, row);
continue;
}
- gtk_widget_unparent (GTK_WIDGET (tile_child->tile));
- g_ptr_array_remove_fast (self->tiles_positions, tile_child);
+ gtk_widget_unparent (GTK_WIDGET (tile));
+ g_hash_table_remove (self->tile_children, &pos);
}
}
}
@@ -246,13 +280,13 @@ recompute_grid (ShumateMapLayer *self,
for (guint row = self->required_tiles_rows; row < required_tiles_rows; row++)
{
ShumateTile *tile;
- TileGridPosition *tile_child;
+ TileGridPosition *pos;
tile = shumate_tile_new ();
shumate_tile_set_size (tile, tile_size);
gtk_widget_insert_before (GTK_WIDGET (tile), widget, NULL);
- tile_child = tile_grid_position_new (tile, column, row);
- g_ptr_array_add (self->tiles_positions, tile_child);
+ pos = tile_grid_position_new (column, row);
+ g_hash_table_insert (self->tile_children, pos, g_object_ref (tile));
}
}
}
@@ -262,15 +296,20 @@ recompute_grid (ShumateMapLayer *self,
{
for (guint row = self->required_tiles_rows - 1; row >= required_tiles_rows; row--)
{
- TileGridPosition *tile_child = shumate_map_layer_get_tile_child (self, column, row);
- if (!tile_child)
+ TileGridPosition pos;
+ ShumateTile *tile;
+
+ tile_grid_position_init (&pos, column, row);
+ tile = g_hash_table_lookup (self->tile_children, &pos);
+
+ if (!tile)
{
g_critical ("Unable to find tile to remove at (%u;%u)", column, row);
continue;
}
- gtk_widget_unparent (GTK_WIDGET (tile_child->tile));
- g_ptr_array_remove_fast (self->tiles_positions, tile_child);
+ gtk_widget_unparent (GTK_WIDGET (tile));
+ g_hash_table_remove (self->tile_children, &pos);
}
}
}
@@ -423,7 +462,7 @@ shumate_map_layer_dispose (GObject *object)
g_clear_handle_id (&self->recompute_grid_idle_id, g_source_remove);
g_clear_pointer (&self->tile_fill, g_hash_table_unref);
- g_clear_pointer (&self->tiles_positions, g_ptr_array_unref);
+ g_clear_pointer (&self->tile_children, g_hash_table_unref);
g_clear_object (&self->map_source);
g_clear_object (&self->memcache);
@@ -530,18 +569,15 @@ shumate_map_layer_size_allocate (GtkWidget *widget,
tile_column = tile_initial_column;
for (int column = 0; column < self->required_tiles_columns; column++)
{
- TileGridPosition *tile_child;
ShumateTile *child;
- tile_child = shumate_map_layer_get_tile_child (self, column, row);
- if (!tile_child)
+ child = shumate_map_layer_get_tile_child (self, column, row);
+ if (!child)
{
g_critical ("Unable to find tile at (%u;%u)", column, row);
continue;
}
- child = tile_child->tile;
-
gtk_widget_measure (GTK_WIDGET (child), GTK_ORIENTATION_HORIZONTAL, 0, NULL, NULL, NULL, NULL);
gtk_widget_size_allocate (GTK_WIDGET (child), &child_allocation, baseline);
@@ -560,11 +596,11 @@ shumate_map_layer_size_allocate (GtkWidget *widget,
shumate_tile_set_x (child, tile_column % source_columns);
shumate_tile_set_y (child, tile_row % source_rows);
- if (!shumate_memory_cache_try_fill_tile (self->memcache, tile_child->tile, source_id))
+ if (!shumate_memory_cache_try_fill_tile (self->memcache, child, source_id))
{
TileFilledData *data = g_new0 (TileFilledData, 1);
data->self = g_object_ref (self);
- data->tile = g_object_ref (tile_child->tile);
+ data->tile = g_object_ref (child);
data->source_id = g_strdup (source_id);
cancellable = g_cancellable_new ();
@@ -670,7 +706,7 @@ shumate_map_layer_class_init (ShumateMapLayerClass *klass)
static void
shumate_map_layer_init (ShumateMapLayer *self)
{
- self->tiles_positions = g_ptr_array_new_with_free_func ((GDestroyNotify) tile_grid_position_free);
+ self->tile_children = g_hash_table_new_full (tile_grid_position_hash, tile_grid_position_equal,
tile_grid_position_free, g_object_unref);
self->tile_fill = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, g_object_unref);
self->memcache = shumate_memory_cache_new_full (100);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]