Add GtkArrayStore

This has roughly the same API as GListStore, it's just an array.
This commit is contained in:
Benjamin Otte
2020-07-02 17:46:06 +02:00
parent 663ca21328
commit 59aaabb161
4 changed files with 344 additions and 0 deletions

View File

@@ -44,6 +44,7 @@
#include <gtk/gtkappchooserbutton.h>
#include <gtk/gtkapplication.h>
#include <gtk/gtkapplicationwindow.h>
#include <gtk/gtkarraystore.h>
#include <gtk/gtkaspectframe.h>
#include <gtk/gtkassistant.h>
#include <gtk/gtkbinlayout.h>

287
gtk/gtkarraystore.c Normal file
View File

@@ -0,0 +1,287 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkarraystore.h"
#define GTK_VECTOR_ELEMENT_TYPE GObject *
#define GTK_VECTOR_FREE_FUNC g_object_unref
#include "gtkvectorimpl.c"
/**
* SECTION:gtkarraystore
* @title: GtkArrayStore
* @short_description: A simple array implementation of #GListModel
*
* #GtkArrayStore is a simple implementation of #GListModel that stores all
* items in memory.
*
* It provides appending, deletions, and lookups in O(1) time and insertions
* in O(N) time. it is implemented using an array.
*/
/**
* GtkArrayStore:
*
* #GtkArrayStore is an opaque data structure and can only be accessed
* using the following functions.
**/
struct _GtkArrayStore
{
GObject parent_instance;
GType item_type;
GtkVector items;
};
enum
{
PROP_0,
PROP_ITEM_TYPE,
N_PROPERTIES
};
static void gtk_array_store_iface_init (GListModelInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkArrayStore, gtk_array_store, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_array_store_iface_init));
static void
gtk_array_store_dispose (GObject *object)
{
GtkArrayStore *self = GTK_ARRAY_STORE (object);
gtk_vector_clear (&self->items);
G_OBJECT_CLASS (gtk_array_store_parent_class)->dispose (object);
}
static void
gtk_array_store_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkArrayStore *self = GTK_ARRAY_STORE (object);
switch (property_id)
{
case PROP_ITEM_TYPE:
g_value_set_gtype (value, self->item_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
gtk_array_store_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkArrayStore *self = GTK_ARRAY_STORE (object);
switch (property_id)
{
case PROP_ITEM_TYPE: /* construct-only */
g_assert (g_type_is_a (g_value_get_gtype (value), G_TYPE_OBJECT));
self->item_type = g_value_get_gtype (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
gtk_array_store_class_init (GtkArrayStoreClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_array_store_dispose;
object_class->get_property = gtk_array_store_get_property;
object_class->set_property = gtk_array_store_set_property;
/**
* GtkArrayStore:item-type:
*
* The type of items contained in this list self. Items must be
* subclasses of #GObject.
**/
g_object_class_install_property (object_class, PROP_ITEM_TYPE,
g_param_spec_gtype ("item-type", "", "", G_TYPE_OBJECT,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static GType
gtk_array_store_get_item_type (GListModel *list)
{
GtkArrayStore *self = GTK_ARRAY_STORE (list);
return self->item_type;
}
static guint
gtk_array_store_get_n_items (GListModel *list)
{
GtkArrayStore *self = GTK_ARRAY_STORE (list);
return gtk_vector_get_size (&self->items);
}
static gpointer
gtk_array_store_get_item (GListModel *list,
guint position)
{
GtkArrayStore *self = GTK_ARRAY_STORE (list);
if (position >= gtk_vector_get_size (&self->items))
return NULL;
return g_object_ref (gtk_vector_get (&self->items, position));
}
static void
gtk_array_store_iface_init (GListModelInterface *iface)
{
iface->get_item_type = gtk_array_store_get_item_type;
iface->get_n_items = gtk_array_store_get_n_items;
iface->get_item = gtk_array_store_get_item;
}
static void
gtk_array_store_init (GtkArrayStore *self)
{
gtk_vector_init (&self->items);
}
/**
* gtk_array_store_new:
* @item_type: the #GType of items in the list
*
* Creates a new #GtkArrayStore with items of type @item_type. @item_type
* must be a subclass of #GObject.
*
* Returns: a new #GtkArrayStore
*/
GtkArrayStore *
gtk_array_store_new (GType item_type)
{
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
return g_object_new (GTK_TYPE_ARRAY_STORE,
"item-type", item_type,
NULL);
}
/**
* gtk_array_store_append:
* @self: a #GtkArrayStore
* @item: (type GObject): the new item
*
* Appends @item to @self. @item must be of type #GtkArrayStore:item-type.
*
* This function takes a ref on @item.
*
* Use gtk_array_store_splice() to append multiple items at the same time
* efficiently.
*/
void
gtk_array_store_append (GtkArrayStore *self,
gpointer item)
{
guint position;
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (item), self->item_type));
position = gtk_vector_get_size (&self->items);
gtk_vector_append (&self->items, g_object_ref (item));
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
}
/**
* gtk_array_store_remove_all:
* @self: a #GtkArrayStore
*
* Removes all items from @self.
*
* Since: 2.44
*/
void
gtk_array_store_remove_all (GtkArrayStore *self)
{
guint n_items;
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
n_items = gtk_vector_get_size (&self->items);
gtk_vector_clear (&self->items);
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, 0);
}
/**
* gtk_array_store_splice:
* @self: a #GtkArrayStore
* @position: the position at which to make the change
* @n_removals: the number of items to remove
* @additions: (array length=n_additions) (element-type GObject): the items to add
* @n_additions: the number of items to add
*
* Changes @self by removing @n_removals items and adding @n_additions
* items to it. @additions must contain @n_additions items of type
* #GtkArrayStore:item-type. %NULL is not permitted.
*
* This function is more efficient than gtk_array_store_insert() and
* gtk_array_store_remove(), because it only emits
* #GListModel::items-changed once for the change.
*
* This function takes a ref on each item in @additions.
*
* The parameters @position and @n_removals must be correct (ie:
* @position + @n_removals must be less than or equal to the length of
* the list at the time this function is called).
*
* Since: 2.44
*/
void
gtk_array_store_splice (GtkArrayStore *self,
guint position,
guint n_removals,
gpointer *additions,
guint n_additions)
{
guint i;
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
g_return_if_fail (position + n_removals >= position); /* overflow */
g_return_if_fail (position + n_removals <= gtk_vector_get_size (&self->items));
for (i = 0; i < n_additions; i++)
g_object_ref (additions[i]);
gtk_vector_splice (&self->items, position, n_removals, (GObject **) additions, n_additions);
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, n_additions);
}

54
gtk/gtkarraystore.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* Copyright © 2020 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __GTK_ARRAY_STORE_H__
#define __GTK_ARRAY_STORE_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GTK_TYPE_ARRAY_STORE (gtk_array_store_get_type ())
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE(GtkArrayStore, gtk_array_store, GTK, ARRAY_STORE, GObject)
GDK_AVAILABLE_IN_ALL
GtkArrayStore * gtk_array_store_new (GType item_type);
GDK_AVAILABLE_IN_ALL
void gtk_array_store_append (GtkArrayStore *store,
gpointer item);
GDK_AVAILABLE_IN_ALL
void gtk_array_store_remove_all (GtkArrayStore *store);
GDK_AVAILABLE_IN_ALL
void gtk_array_store_splice (GtkArrayStore *store,
guint position,
guint n_removals,
gpointer *additions,
guint n_additions);
G_END_DECLS
#endif /* __GTK_ARRAY_STORE_H__ */

View File

@@ -160,6 +160,7 @@ gtk_public_sources = files([
'gtkappchooserwidget.c',
'gtkapplication.c',
'gtkapplicationwindow.c',
'gtkarraystore.c',
'gtkaspectframe.c',
'gtkassistant.c',
'gtkbinlayout.c',
@@ -447,6 +448,7 @@ gtk_public_headers = files([
'gtkappchooserwidget.h',
'gtkapplication.h',
'gtkapplicationwindow.h',
'gtkarraystore.h',
'gtkaspectframe.h',
'gtkassistant.h',
'gtkbinlayout.h',