forked from AuroraMiddleware/gtk
sorter: Introduce GtkSortKeys
GtkSortKeys is an immutable struct that can be used to manage "sort keys" for items. Sort keys are memory that is created specifically for sorting. Because sorting involves lots of comparisons, it's a good idea to prepare the data relevant for sorting in advance and sort on that data. In measurements with a PropertyExpression on a string sorter, it's about ??? faster
This commit is contained in:
parent
8c608e9c1c
commit
e34c7e6796
153
gtk/gtksorter.c
153
gtk/gtksorter.c
@ -19,7 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtksorter.h"
|
||||
#include "gtksorterprivate.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
@ -48,12 +48,26 @@
|
||||
* and provide one's own sorter.
|
||||
*/
|
||||
|
||||
typedef struct _GtkSorterPrivate GtkSorterPrivate;
|
||||
typedef struct _GtkDefaultSortKeys GtkDefaultSortKeys;
|
||||
|
||||
struct _GtkSorterPrivate
|
||||
{
|
||||
GtkSortKeys *keys;
|
||||
};
|
||||
|
||||
struct _GtkDefaultSortKeys
|
||||
{
|
||||
GtkSortKeys keys;
|
||||
GtkSorter *sorter;
|
||||
};
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkSorter, gtk_sorter, G_TYPE_OBJECT)
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkSorter, gtk_sorter, G_TYPE_OBJECT)
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
@ -73,9 +87,24 @@ gtk_sorter_default_get_order (GtkSorter *self)
|
||||
return GTK_SORTER_ORDER_PARTIAL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sorter_dispose (GObject *object)
|
||||
{
|
||||
GtkSorter *self = GTK_SORTER (object);
|
||||
GtkSorterPrivate *priv = gtk_sorter_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->keys, gtk_sort_keys_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_sorter_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sorter_class_init (GtkSorterClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = gtk_sorter_dispose;
|
||||
|
||||
class->compare = gtk_sorter_default_compare;
|
||||
class->get_order = gtk_sorter_default_get_order;
|
||||
|
||||
@ -181,6 +210,98 @@ gtk_sorter_get_order (GtkSorter *self)
|
||||
return GTK_SORTER_GET_CLASS (self)->get_order (self);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_default_sort_keys_compare (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer data)
|
||||
{
|
||||
GtkDefaultSortKeys *self = data;
|
||||
gpointer *key_a = (gpointer *) a;
|
||||
gpointer *key_b = (gpointer *) b;
|
||||
|
||||
return gtk_sorter_compare (self->sorter, *key_a, *key_b);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_default_sort_keys_free (GtkSortKeys *keys)
|
||||
{
|
||||
GtkDefaultSortKeys *self = (GtkDefaultSortKeys *) keys;
|
||||
|
||||
g_object_unref (self->sorter);
|
||||
|
||||
g_slice_free (GtkDefaultSortKeys, self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_default_sort_keys_is_compatible (GtkSortKeys *keys,
|
||||
GtkSortKeys *other)
|
||||
{
|
||||
if (keys->klass != other->klass)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_default_sort_keys_init_key (GtkSortKeys *self,
|
||||
gpointer item,
|
||||
gpointer key_memory)
|
||||
{
|
||||
gpointer *key = (gpointer *) key_memory;
|
||||
|
||||
*key = g_object_ref (item);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_default_sort_keys_clear_key (GtkSortKeys *self,
|
||||
gpointer key_memory)
|
||||
{
|
||||
gpointer *key = (gpointer *) key_memory;
|
||||
|
||||
g_object_unref (*key);
|
||||
}
|
||||
|
||||
static const GtkSortKeysClass GTK_DEFAULT_SORT_KEYS_CLASS =
|
||||
{
|
||||
gtk_default_sort_keys_free,
|
||||
gtk_default_sort_keys_compare,
|
||||
gtk_default_sort_keys_is_compatible,
|
||||
gtk_default_sort_keys_init_key,
|
||||
gtk_default_sort_keys_clear_key,
|
||||
};
|
||||
|
||||
/*<private>
|
||||
* gtk_sorter_get_keys:
|
||||
* @self: a #GtkSorter
|
||||
*
|
||||
* Gets a #GtkSortKeys that can be used as an alternative to
|
||||
* @self for faster sorting.
|
||||
*
|
||||
* The sort keys can change every time #GtkSorter::changed is emitted.
|
||||
* When the keys change, you should redo all comparisons with the new
|
||||
* keys.
|
||||
* When gtk_sort_keys_is_compatible() for the old and new keys returns
|
||||
* %TRUE, you can reuse keys you generated previously.
|
||||
*
|
||||
* Returns: (transfer full): the sort keys to sort with
|
||||
**/
|
||||
GtkSortKeys *
|
||||
gtk_sorter_get_keys (GtkSorter *self)
|
||||
{
|
||||
GtkSorterPrivate *priv = gtk_sorter_get_instance_private (self);
|
||||
GtkDefaultSortKeys *fallback;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SORTER (self), NULL);
|
||||
|
||||
if (priv->keys)
|
||||
return gtk_sort_keys_ref (priv->keys);
|
||||
|
||||
fallback = gtk_sort_keys_new (GtkDefaultSortKeys, >K_DEFAULT_SORT_KEYS_CLASS, sizeof (gpointer), sizeof (gpointer));
|
||||
fallback->sorter = g_object_ref (self);
|
||||
|
||||
return (GtkSortKeys *) fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sorter_changed:
|
||||
* @self: a #GtkSorter
|
||||
@ -205,3 +326,31 @@ gtk_sorter_changed (GtkSorter *self,
|
||||
|
||||
g_signal_emit (self, signals[CHANGED], 0, change);
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gtk_sorter_changed_with_keys
|
||||
* @self: a #GtkSorter
|
||||
* @change: How the sorter changed
|
||||
* @keys: (not nullable) (transfer full): New keys to use
|
||||
*
|
||||
* Updates the sorter's keys to @keys and then calls gtk_sorter_changed().
|
||||
* If you do not want to update the keys, call that function instead.
|
||||
*
|
||||
* This function should also be called in your_sorter_init() to initialize
|
||||
* the keys to use with your sorter.
|
||||
*/
|
||||
void
|
||||
gtk_sorter_changed_with_keys (GtkSorter *self,
|
||||
GtkSorterChange change,
|
||||
GtkSortKeys *keys)
|
||||
{
|
||||
GtkSorterPrivate *priv = gtk_sorter_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (GTK_IS_SORTER (self));
|
||||
g_return_if_fail (keys != NULL);
|
||||
|
||||
g_clear_pointer (&priv->keys, gtk_sort_keys_unref);
|
||||
priv->keys = keys;
|
||||
|
||||
gtk_sorter_changed (self, change);
|
||||
}
|
||||
|
@ -115,6 +115,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sorter_changed (GtkSorter *self,
|
||||
GtkSorterChange change);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SORTER_H__ */
|
||||
|
33
gtk/gtksorterprivate.h
Normal file
33
gtk/gtksorterprivate.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SORTER_PRIVATE_H__
|
||||
#define __GTK_SORTER_PRIVATE_H__
|
||||
|
||||
#include <gtk/gtksorter.h>
|
||||
|
||||
#include "gtk/gtksortkeysprivate.h"
|
||||
|
||||
GtkSortKeys * gtk_sorter_get_keys (GtkSorter *self);
|
||||
|
||||
void gtk_sorter_changed_with_keys (GtkSorter *self,
|
||||
GtkSorterChange change,
|
||||
GtkSortKeys *keys);
|
||||
|
||||
|
||||
#endif /* __GTK_SORTER_PRIVATE_H__ */
|
||||
|
97
gtk/gtksortkeys.c
Normal file
97
gtk/gtksortkeys.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtksortkeysprivate.h"
|
||||
|
||||
#include "gtkcssstyleprivate.h"
|
||||
#include "gtkstyleproviderprivate.h"
|
||||
|
||||
GtkSortKeys *
|
||||
gtk_sort_keys_alloc (const GtkSortKeysClass *klass,
|
||||
gsize size,
|
||||
gsize key_size,
|
||||
gsize key_align)
|
||||
{
|
||||
GtkSortKeys *self;
|
||||
|
||||
g_return_val_if_fail (key_align > 0, NULL);
|
||||
|
||||
self = g_slice_alloc0 (size);
|
||||
|
||||
self->klass = klass;
|
||||
self->ref_count = 1;
|
||||
|
||||
self->key_size = key_size;
|
||||
self->key_align = key_align;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
GtkSortKeys *
|
||||
gtk_sort_keys_ref (GtkSortKeys *self)
|
||||
{
|
||||
self->ref_count += 1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_sort_keys_unref (GtkSortKeys *self)
|
||||
{
|
||||
self->ref_count -= 1;
|
||||
if (self->ref_count > 0)
|
||||
return;
|
||||
|
||||
self->klass->free (self);
|
||||
}
|
||||
|
||||
gsize
|
||||
gtk_sort_keys_get_key_size (GtkSortKeys *self)
|
||||
{
|
||||
return self->key_size;
|
||||
}
|
||||
|
||||
gsize
|
||||
gtk_sort_keys_get_key_align (GtkSortKeys *self)
|
||||
{
|
||||
return self->key_align;
|
||||
}
|
||||
|
||||
GCompareDataFunc
|
||||
gtk_sort_keys_get_key_compare_func (GtkSortKeys *self)
|
||||
{
|
||||
return self->klass->key_compare;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_sort_keys_is_compatible (GtkSortKeys *self,
|
||||
GtkSortKeys *other)
|
||||
{
|
||||
if (self == other)
|
||||
return TRUE;
|
||||
|
||||
return self->klass->is_compatible (self, other);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_sort_keys_needs_clear_key (GtkSortKeys *self)
|
||||
{
|
||||
return self->klass->clear_key != NULL;
|
||||
}
|
||||
|
95
gtk/gtksortkeysprivate.h
Normal file
95
gtk/gtksortkeysprivate.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SORT_KEYS_PRIVATE_H__
|
||||
#define __GTK_SORT_KEYS_PRIVATE_H__
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gtk/gtkenums.h>
|
||||
#include <gtk/gtksorter.h>
|
||||
|
||||
typedef struct _GtkSortKeys GtkSortKeys;
|
||||
typedef struct _GtkSortKeysClass GtkSortKeysClass;
|
||||
|
||||
struct _GtkSortKeys
|
||||
{
|
||||
const GtkSortKeysClass *klass;
|
||||
gint ref_count;
|
||||
|
||||
gsize key_size;
|
||||
gsize key_align; /* must be power of 2 */
|
||||
};
|
||||
|
||||
struct _GtkSortKeysClass
|
||||
{
|
||||
void (* free) (GtkSortKeys *self);
|
||||
|
||||
GCompareDataFunc key_compare;
|
||||
|
||||
gboolean (* is_compatible) (GtkSortKeys *self,
|
||||
GtkSortKeys *other);
|
||||
|
||||
void (* init_key) (GtkSortKeys *self,
|
||||
gpointer item,
|
||||
gpointer key_memory);
|
||||
void (* clear_key) (GtkSortKeys *self,
|
||||
gpointer key_memory);
|
||||
};
|
||||
|
||||
GtkSortKeys * gtk_sort_keys_alloc (const GtkSortKeysClass *klass,
|
||||
gsize size,
|
||||
gsize key_size,
|
||||
gsize key_align);
|
||||
#define gtk_sort_keys_new(_name, _klass, _key_size, _key_align) \
|
||||
((_name *) gtk_sort_keys_alloc ((_klass), sizeof (_name), (_key_size), (_key_align)))
|
||||
GtkSortKeys * gtk_sort_keys_ref (GtkSortKeys *self);
|
||||
void gtk_sort_keys_unref (GtkSortKeys *self);
|
||||
|
||||
gsize gtk_sort_keys_get_key_size (GtkSortKeys *self);
|
||||
gsize gtk_sort_keys_get_key_align (GtkSortKeys *self);
|
||||
GCompareDataFunc gtk_sort_keys_get_key_compare_func (GtkSortKeys *self);
|
||||
gboolean gtk_sort_keys_is_compatible (GtkSortKeys *self,
|
||||
GtkSortKeys *other);
|
||||
gboolean gtk_sort_keys_needs_clear_key (GtkSortKeys *self);
|
||||
|
||||
#define GTK_SORT_KEYS_ALIGN(_size,_align) (((_size) + (_align) - 1) & ~((_align) - 1))
|
||||
static inline int
|
||||
gtk_sort_keys_compare (GtkSortKeys *self,
|
||||
gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
return self->klass->key_compare (a, b, self);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_sort_keys_init_key (GtkSortKeys *self,
|
||||
gpointer item,
|
||||
gpointer key_memory)
|
||||
{
|
||||
self->klass->init_key (self, item, key_memory);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_sort_keys_clear_key (GtkSortKeys *self,
|
||||
gpointer key_memory)
|
||||
{
|
||||
if (self->klass->clear_key)
|
||||
self->klass->clear_key (self, key_memory);
|
||||
}
|
||||
|
||||
#endif /* __GTK_SORT_KEYS_PRIVATE_H__ */
|
||||
|
@ -133,6 +133,7 @@ gtk_private_sources = files([
|
||||
'gtksearchengine.c',
|
||||
'gtksearchenginemodel.c',
|
||||
'gtksizerequestcache.c',
|
||||
'gtksortkeys.c',
|
||||
'gtkstyleanimation.c',
|
||||
'gtkstylecascade.c',
|
||||
'gtkstyleproperty.c',
|
||||
|
Loading…
Reference in New Issue
Block a user