Re: gbsearcharray
- From: Joshua N Pritikin <vishnu pobox com>
- To: Tim Janik <timj gtk org>
- Cc: Gtk+ Developers <gtk-devel-list gnome org>
- Subject: Re: gbsearcharray
- Date: Sat, 25 Aug 2001 22:56:27 +0530
On Sat, Aug 25, 2001 at 03:10:58PM +0200, Tim Janik wrote:
> 1) gbsearcharray.[hc] should prolly be moved into glib/glib/
i was surprised to see this because i recently implemented a similar
data structure adapted from g_ptr_array. (Attached.)
Please forgive any mistakes in convention -- gptrset is a work in progress.
gptrset was written to make an easier GtkListStore. It emits almost the
exact signals which are wanted by GtkTreeModel.
It seems like there are lots of slightly different ways to implement the
same "array of stuff" data structure. Please consider gptrset in view of
glib's aims of avoid bloat yet offering the most useful data structures. ;-)
--
Get self-realization at <http://sahajayoga.org> ... <http://why-compete.org> ?
Victory to the Divine Mother!!
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* originally adapted from g_ptr_array */
#ifndef _G_PTRSET_H_
#define _G_PTRSET_H_
#include <glib-object.h>
typedef struct _GPtrSetClass GPtrSetClass;
typedef struct _GPtrSet GPtrSet;
#define G_TYPE_PTR_SET (g_ptr_set_get_type())
#define G_PTR_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PTR_SET, GPtrSet))
#define G_IS_PTR_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PTR_SET))
#define G_PTR_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PTR_SET, GPtrSetClass))
#define G_PTR_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PTR_SET, GPtrSetClass))
#define G_IS_PTR_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PTR_SET))
struct _GPtrSet
{
GObject parent_instance;
gpointer * pdata;
gint len;
gint alloc;
gconstpointer compare_data;
GCompareDataFunc ptr_compare;
GCompareDataFunc key_compare;
GDestroyNotify destroy_func;
guint objects : 1; /* whether to use g_object_{ref|unref} */
};
#define g_ptr_set_at(set,index) ((set)->pdata)[(index)]
GType g_ptr_set_get_type ();
GPtrSet * g_ptr_set_new ();
GPtrSet * g_ptr_set_new (GCompareDataFunc ptr_compare,
gconstpointer compare_data);
void g_ptr_set_set_key_compare (GPtrSet *set,
GCompareDataFunc key_compare);
void g_ptr_set_free (GPtrSet *set);
gboolean g_ptr_set_lookup (GPtrSet * set,
gint * ret,
gconstpointer sample);
gboolean g_ptr_set_lookup_key (GPtrSet * set,
gint * ret,
gconstpointer sample_key);
gpointer g_ptr_set_remove_index (GPtrSet * set,
gint index);
gboolean g_ptr_set_remove (GPtrSet * set,
gpointer data);
void g_ptr_set_add_index (GPtrSet * set,
gint index,
gpointer data);
void g_ptr_set_add (GPtrSet * set,
gpointer data);
void g_ptr_set_reorder (GPtrSet * set,
gint index);
#endif
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <glib.h>
#include <string.h>
#include "gptrset.h"
#include "appmarshal.h"
struct _GPtrSetClass {
GObjectClass parent_class;
void (*deleted) (GPtrSet *set, gint index, gpointer data);
void (*inserted) (GPtrSet *set, gint index);
void (*reordered) (GPtrSet *set, gint old_order, gint new_order);
};
enum {
PROP_0,
PROP_COMPARE_DATA,
PROP_KEY_COMPARE,
PROP_PTR_COMPARE,
PROP_DESTROY_FUNC,
PROP_OBJECTS
};
enum {
DELETED,
INSERTED,
REORDERED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
#define MIN_SET_SIZE 16
static void g_ptr_set_maybe_expand (GPtrSet *set,
gint len);
static gint
g_nearest_pow (gint num)
{
gint n = 1;
while (n < num)
n <<= 1;
return n;
}
GPtrSet *
g_ptr_set_new (GCompareDataFunc ptr_compare,
gconstpointer compare_data)
{
GPtrSet *set;
set = G_PTR_SET (g_object_new (g_ptr_set_get_type(), 0));
set->ptr_compare = ptr_compare;
set->compare_data = compare_data;
return set;
}
void
g_ptr_set_set_key_compare (GPtrSet *set, GCompareDataFunc key_compare)
{
set->key_compare = key_compare;
}
static void
g_ptr_set_init (GPtrSet *set)
{
/* zero fill is good */
}
// g_ptr_set_maybe_shrink XXX
static void
g_ptr_set_maybe_expand (GPtrSet *set,
gint len)
{
if ((set->len + len) > set->alloc)
{
#ifdef ENABLE_GC_FRIENDLY
gint old_alloc = set->alloc;
#endif /* ENABLE_GC_FRIENDLY */
set->alloc = g_nearest_pow (set->len + len);
set->alloc = MAX (set->alloc, MIN_SET_SIZE);
set->pdata = g_realloc (set->pdata, sizeof(gpointer) * set->alloc);
#ifdef ENABLE_GC_FRIENDLY
for ( ; old_alloc < set->alloc; old_alloc++)
set->pdata [old_alloc] = NULL;
#endif /* ENABLE_GC_FRIENDLY */
}
}
static gboolean
_ptr_set_lookup (GPtrSet * fset,
gint * ret,
GCompareDataFunc compare,
gconstpointer sample)
{
gint first, last;
gint mid;
gint midsize;
gint cmp;
gint tx;
g_return_val_if_fail (compare, FALSE);
g_return_val_if_fail (sample, FALSE);
if (!fset->len)
{
if (ret) *ret = 0;
return FALSE;
}
first = 0;
last = fset->len - 1;
midsize = last - first;
while (midsize > 1) {
mid = first + midsize / 2;
cmp = (*compare) (sample, g_ptr_set_at (fset, mid), (gpointer) fset->compare_data);
if (cmp == 0)
{
if (ret) *ret = mid;
return TRUE;
}
if (cmp < 0)
last = mid-1;
else
first = mid+1;
midsize = last - first;
}
for (tx = first; tx <= last; tx++)
{
cmp = (*compare) (sample, g_ptr_set_at (fset, tx), (gpointer) fset->compare_data);
if (cmp < 0)
{
if (ret) *ret = tx;
return FALSE;
}
if (cmp == 0)
{
if (ret) *ret = tx;
return TRUE;
}
}
if (ret) *ret = last+1;
return FALSE;
}
gboolean
g_ptr_set_lookup (GPtrSet * fset,
gint * ret,
gconstpointer sample)
{
g_return_val_if_fail (fset, FALSE);
return _ptr_set_lookup (fset, ret, fset->ptr_compare, sample);
}
gboolean
g_ptr_set_lookup_key (GPtrSet * set,
gint * ret,
gconstpointer sample_key)
{
g_return_val_if_fail (set, FALSE);
return _ptr_set_lookup (set, ret, set->key_compare, sample_key);
}
static inline void
g_ptr_set_verify_sort (GPtrSet * set)
{
gint xx;
if (set->len <= 1)
return;
for (xx=0; xx < set->len - 1; xx++)
{
if (set->ptr_compare (g_ptr_set_at (set, xx),
g_ptr_set_at (set, xx + 1),
(gpointer) set->compare_data) > 0)
g_critical ("%d, %d are unsorted", xx, xx+1);
}
}
void
g_ptr_set_reorder (GPtrSet * set,
gint index)
{
gpointer data;
gint mx;
g_return_if_fail (set);
g_return_if_fail (0 <= index && index < set->len);
data = g_ptr_set_at (set, index);
if (index != set->len - 1)
g_memmove (set->pdata + index, set->pdata + index + 1,
sizeof (gpointer) * (set->len - index - 1));
-- set->len;
g_ptr_set_lookup (set, &mx, data);
g_memmove (&g_ptr_set_at (set, 1 + mx),
&g_ptr_set_at (set, mx),
sizeof(gpointer) * (set->len - mx));
g_ptr_set_at (set, mx) = data;
++ set->len;
if (mx == index)
return;
g_ptr_set_verify_sort (set);
g_signal_emit (set, signals[REORDERED], 0, index, mx);
}
gpointer
g_ptr_set_remove_index (GPtrSet* fset,
gint index)
{
gpointer result;
g_return_val_if_fail (fset, NULL);
g_return_val_if_fail (0 <= index && index < fset->len, NULL);
result = fset->pdata[index];
if (index != fset->len - 1)
g_memmove (fset->pdata + index, fset->pdata + index + 1,
sizeof (gpointer) * (fset->len - index - 1));
fset->len -= 1;
#ifdef ENABLE_GC_FRIENDLY
fset->pdata[fset->len] = NULL;
#endif /* ENABLE_GC_FRIENDLY */
g_ptr_set_verify_sort (fset);
g_signal_emit (fset, signals[DELETED], 0, index, result);
if (fset->destroy_func)
(*fset->destroy_func) (result);
if (fset->objects)
g_object_unref (result);
return result;
}
gboolean
g_ptr_set_remove (GPtrSet* fset,
gpointer data)
{
gint at;
g_return_val_if_fail (fset, FALSE);
g_return_val_if_fail (data, FALSE);
/* only remove first match */
if (g_ptr_set_lookup (fset, &at, data))
{
g_ptr_set_remove_index (fset, at);
return TRUE;
}
return FALSE;
}
void
g_ptr_set_add_index (GPtrSet * set,
gint index,
gpointer data)
{
g_return_if_fail (set);
g_return_if_fail (0 <= index && index <= set->len);
if (set->objects)
g_object_ref (data);
g_ptr_set_maybe_expand ((GPtrSet*) set, 1);
g_memmove (&g_ptr_set_at (set, 1 + index),
&g_ptr_set_at (set, index),
sizeof(gpointer) * (set->len - index));
g_ptr_set_at (set, index) = data;
set->len += 1;
g_ptr_set_verify_sort (set);
g_signal_emit (set, signals[INSERTED], 0, index);
}
void
g_ptr_set_add (GPtrSet * set,
gpointer data)
{
gint at;
g_return_if_fail (set);
g_return_if_fail (data);
if (g_ptr_set_lookup (set, &at, data))
++at; // reduce memmove
g_ptr_set_add_index (set, at, data);
}
static void
g_ptr_set_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GPtrSet *set = G_PTR_SET (object);
g_return_if_fail (set->len == 0);
switch (prop_id) {
case PROP_COMPARE_DATA:
set->compare_data = g_value_get_pointer (value);
break;
case PROP_KEY_COMPARE:
set->key_compare = g_value_get_pointer (value);
break;
case PROP_PTR_COMPARE:
set->ptr_compare = g_value_get_pointer (value);
break;
case PROP_DESTROY_FUNC:
set->destroy_func = g_value_get_pointer (value);
break;
case PROP_OBJECTS:
set->objects = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
g_ptr_set_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GPtrSet *set = G_PTR_SET (object);
switch (prop_id) {
case PROP_COMPARE_DATA:
g_value_set_pointer (value, (gpointer) set->compare_data);
break;
case PROP_KEY_COMPARE:
g_value_set_pointer (value, set->key_compare);
break;
case PROP_PTR_COMPARE:
g_value_set_pointer (value, set->ptr_compare);
break;
case PROP_DESTROY_FUNC:
g_value_set_pointer (value, set->destroy_func);
break;
case PROP_OBJECTS:
g_value_set_boolean (value, set->objects);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GObjectClass *parent_class;
static void
g_ptr_set_finalize (GObject *object)
{
GPtrSet *set;
gint xx;
g_return_if_fail (G_IS_PTR_SET (object));
set = G_PTR_SET (object);
if (set->destroy_func)
for (xx=0; xx < set->len; xx++)
(* set->destroy_func) (g_ptr_set_at (set, xx));
if (set->objects)
for (xx=0; xx < set->len; xx++)
g_object_unref (g_ptr_set_at (set, xx));
g_free (set->pdata);
set->pdata = NULL;
(* G_OBJECT_CLASS(parent_class)->finalize) (object);
}
static void
g_ptr_set_class_init(GPtrSetClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS(klass);
parent_class = g_type_class_peek_parent (klass);
object_class->set_property = g_ptr_set_set_property;
object_class->get_property = g_ptr_set_get_property;
object_class->finalize = g_ptr_set_finalize;
g_object_class_install_property
(object_class, PROP_COMPARE_DATA,
g_param_spec_pointer ("compare_Data",
"",
"",
G_PARAM_READABLE|G_PARAM_WRITABLE));
g_object_class_install_property
(object_class, PROP_KEY_COMPARE,
g_param_spec_pointer ("key_compare",
"",
"GCompareDataFunc",
G_PARAM_READABLE|G_PARAM_WRITABLE));
g_object_class_install_property
(object_class, PROP_PTR_COMPARE,
g_param_spec_pointer ("ptr_compare",
"",
"GCompareDataFunc",
G_PARAM_READABLE|G_PARAM_WRITABLE));
g_object_class_install_property
(object_class, PROP_DESTROY_FUNC,
g_param_spec_pointer ("destroy_func",
"",
"GDestroyNotify",
G_PARAM_READABLE|G_PARAM_WRITABLE));
g_object_class_install_property
(object_class, PROP_OBJECTS,
g_param_spec_boolean ("objects",
"",
"Whether to do reference count the elements.",
FALSE,
G_PARAM_READABLE|G_PARAM_WRITABLE));
signals[DELETED] =
g_signal_new ("deleted",
G_OBJECT_CLASS_TYPE (object_class),
0,
0,
NULL, NULL,
app_marshal_VOID__UINT_POINTER,
G_TYPE_NONE,
2,
G_TYPE_UINT,
G_TYPE_POINTER);
signals[INSERTED] =
g_signal_new ("inserted",
G_OBJECT_CLASS_TYPE (object_class),
0,
0,
NULL, NULL,
app_marshal_VOID__UINT,
G_TYPE_NONE,
1,
G_TYPE_UINT);
signals[REORDERED] =
g_signal_new ("reordered",
G_OBJECT_CLASS_TYPE (object_class),
0,
0,
NULL, NULL,
app_marshal_VOID__UINT_UINT,
G_TYPE_NONE,
2,
G_TYPE_UINT,
G_TYPE_UINT);
}
GType
g_ptr_set_get_type() {
static GType our_type = 0;
if (our_type == 0) {
static const GTypeInfo our_info = {
sizeof(GPtrSetClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) g_ptr_set_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GPtrSet),
0, /* n_preallocs */
(GInstanceInitFunc) g_ptr_set_init
};
our_type = g_type_register_static (G_TYPE_OBJECT,
"GPtrSet",
&our_info,
0);
}
return our_type;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]