From 808a282944fa92f11da0c7906674769c22cce5ef Mon Sep 17 00:00:00 2001 From: Tim Janik Date: Tue, 19 Aug 2003 02:16:00 +0000 Subject: [PATCH] license change, no restrictions are made in the new license at all, the Tue Aug 19 03:55:29 2003 Tim Janik * glib/gbsearcharray.h: license change, no restrictions are made in the new license at all, the implmentation is simply provided "as is" to allow copy-pasting the code into any third-party app. naturally, the implementation is self-contained within the header file to allow this. default to non-shrinking behaviour, allow users to request shrinking via G_BSEARCH_ARRAY_AUTO_SHRINK. creation, deletion functions are now named g_bsearch_array_create() and g_bsearch_array_free(). fixed const in prototypes, removed cruft. (g_bsearch_array_insert): take only three arguments, do nothing if the node to insert is already there. (g_bsearch_array_replace): insert or replace if the node is already there. (g_bsearch_array_remove): remove nodes by index, the index of a node can be found via g_bsearch_array_get_index(). removed other g_bsearch_array_remove*() variants. (g_bsearch_array_lookup): minor optimizations. (g_bsearch_array_lookup_sibling): return nodes on mismatches. * glib/gbsearcharray.c: removed. --- ChangeLog | 24 +++ ChangeLog.pre-2-10 | 24 +++ ChangeLog.pre-2-12 | 24 +++ ChangeLog.pre-2-4 | 24 +++ ChangeLog.pre-2-6 | 24 +++ ChangeLog.pre-2-8 | 24 +++ glib/Makefile.am | 1 - glib/gbsearcharray.c | 208 ----------------------- glib/gbsearcharray.h | 383 +++++++++++++++++++++++++++++-------------- 9 files changed, 404 insertions(+), 332 deletions(-) delete mode 100644 glib/gbsearcharray.c diff --git a/ChangeLog b/ChangeLog index 841bcc62f..f8bee7535 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +Tue Aug 19 03:55:29 2003 Tim Janik + + * glib/gbsearcharray.h: license change, no restrictions are made + in the new license at all, the implmentation is simply provided + "as is" to allow copy-pasting the code into any third-party app. + naturally, the implementation is self-contained within the header + file to allow this. + default to non-shrinking behaviour, allow users to request shrinking + via G_BSEARCH_ARRAY_AUTO_SHRINK. + creation, deletion functions are now named g_bsearch_array_create() + and g_bsearch_array_free(). + fixed const in prototypes, removed cruft. + (g_bsearch_array_insert): take only three arguments, do nothing if the + node to insert is already there. + (g_bsearch_array_replace): insert or replace if the node is already + there. + (g_bsearch_array_remove): remove nodes by index, the index of a node + can be found via g_bsearch_array_get_index(). + removed other g_bsearch_array_remove*() variants. + (g_bsearch_array_lookup): minor optimizations. + (g_bsearch_array_lookup_sibling): return nodes on mismatches. + + * glib/gbsearcharray.c: removed. + 2003-08-16 Tor Lillqvist Fix #117925 (Dov Grobgeld): diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 841bcc62f..f8bee7535 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,27 @@ +Tue Aug 19 03:55:29 2003 Tim Janik + + * glib/gbsearcharray.h: license change, no restrictions are made + in the new license at all, the implmentation is simply provided + "as is" to allow copy-pasting the code into any third-party app. + naturally, the implementation is self-contained within the header + file to allow this. + default to non-shrinking behaviour, allow users to request shrinking + via G_BSEARCH_ARRAY_AUTO_SHRINK. + creation, deletion functions are now named g_bsearch_array_create() + and g_bsearch_array_free(). + fixed const in prototypes, removed cruft. + (g_bsearch_array_insert): take only three arguments, do nothing if the + node to insert is already there. + (g_bsearch_array_replace): insert or replace if the node is already + there. + (g_bsearch_array_remove): remove nodes by index, the index of a node + can be found via g_bsearch_array_get_index(). + removed other g_bsearch_array_remove*() variants. + (g_bsearch_array_lookup): minor optimizations. + (g_bsearch_array_lookup_sibling): return nodes on mismatches. + + * glib/gbsearcharray.c: removed. + 2003-08-16 Tor Lillqvist Fix #117925 (Dov Grobgeld): diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 841bcc62f..f8bee7535 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,27 @@ +Tue Aug 19 03:55:29 2003 Tim Janik + + * glib/gbsearcharray.h: license change, no restrictions are made + in the new license at all, the implmentation is simply provided + "as is" to allow copy-pasting the code into any third-party app. + naturally, the implementation is self-contained within the header + file to allow this. + default to non-shrinking behaviour, allow users to request shrinking + via G_BSEARCH_ARRAY_AUTO_SHRINK. + creation, deletion functions are now named g_bsearch_array_create() + and g_bsearch_array_free(). + fixed const in prototypes, removed cruft. + (g_bsearch_array_insert): take only three arguments, do nothing if the + node to insert is already there. + (g_bsearch_array_replace): insert or replace if the node is already + there. + (g_bsearch_array_remove): remove nodes by index, the index of a node + can be found via g_bsearch_array_get_index(). + removed other g_bsearch_array_remove*() variants. + (g_bsearch_array_lookup): minor optimizations. + (g_bsearch_array_lookup_sibling): return nodes on mismatches. + + * glib/gbsearcharray.c: removed. + 2003-08-16 Tor Lillqvist Fix #117925 (Dov Grobgeld): diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 841bcc62f..f8bee7535 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,27 @@ +Tue Aug 19 03:55:29 2003 Tim Janik + + * glib/gbsearcharray.h: license change, no restrictions are made + in the new license at all, the implmentation is simply provided + "as is" to allow copy-pasting the code into any third-party app. + naturally, the implementation is self-contained within the header + file to allow this. + default to non-shrinking behaviour, allow users to request shrinking + via G_BSEARCH_ARRAY_AUTO_SHRINK. + creation, deletion functions are now named g_bsearch_array_create() + and g_bsearch_array_free(). + fixed const in prototypes, removed cruft. + (g_bsearch_array_insert): take only three arguments, do nothing if the + node to insert is already there. + (g_bsearch_array_replace): insert or replace if the node is already + there. + (g_bsearch_array_remove): remove nodes by index, the index of a node + can be found via g_bsearch_array_get_index(). + removed other g_bsearch_array_remove*() variants. + (g_bsearch_array_lookup): minor optimizations. + (g_bsearch_array_lookup_sibling): return nodes on mismatches. + + * glib/gbsearcharray.c: removed. + 2003-08-16 Tor Lillqvist Fix #117925 (Dov Grobgeld): diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 841bcc62f..f8bee7535 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,27 @@ +Tue Aug 19 03:55:29 2003 Tim Janik + + * glib/gbsearcharray.h: license change, no restrictions are made + in the new license at all, the implmentation is simply provided + "as is" to allow copy-pasting the code into any third-party app. + naturally, the implementation is self-contained within the header + file to allow this. + default to non-shrinking behaviour, allow users to request shrinking + via G_BSEARCH_ARRAY_AUTO_SHRINK. + creation, deletion functions are now named g_bsearch_array_create() + and g_bsearch_array_free(). + fixed const in prototypes, removed cruft. + (g_bsearch_array_insert): take only three arguments, do nothing if the + node to insert is already there. + (g_bsearch_array_replace): insert or replace if the node is already + there. + (g_bsearch_array_remove): remove nodes by index, the index of a node + can be found via g_bsearch_array_get_index(). + removed other g_bsearch_array_remove*() variants. + (g_bsearch_array_lookup): minor optimizations. + (g_bsearch_array_lookup_sibling): return nodes on mismatches. + + * glib/gbsearcharray.c: removed. + 2003-08-16 Tor Lillqvist Fix #117925 (Dov Grobgeld): diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 841bcc62f..f8bee7535 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,27 @@ +Tue Aug 19 03:55:29 2003 Tim Janik + + * glib/gbsearcharray.h: license change, no restrictions are made + in the new license at all, the implmentation is simply provided + "as is" to allow copy-pasting the code into any third-party app. + naturally, the implementation is self-contained within the header + file to allow this. + default to non-shrinking behaviour, allow users to request shrinking + via G_BSEARCH_ARRAY_AUTO_SHRINK. + creation, deletion functions are now named g_bsearch_array_create() + and g_bsearch_array_free(). + fixed const in prototypes, removed cruft. + (g_bsearch_array_insert): take only three arguments, do nothing if the + node to insert is already there. + (g_bsearch_array_replace): insert or replace if the node is already + there. + (g_bsearch_array_remove): remove nodes by index, the index of a node + can be found via g_bsearch_array_get_index(). + removed other g_bsearch_array_remove*() variants. + (g_bsearch_array_lookup): minor optimizations. + (g_bsearch_array_lookup_sibling): return nodes on mismatches. + + * glib/gbsearcharray.c: removed. + 2003-08-16 Tor Lillqvist Fix #117925 (Dov Grobgeld): diff --git a/glib/Makefile.am b/glib/Makefile.am index 2f3a007ad..75c00b771 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -45,7 +45,6 @@ libglib_2_0_la_SOURCES = \ garray.c \ gasyncqueue.c \ gbacktrace.c \ - gbsearcharray.c \ gbsearcharray.h \ gcache.c \ gcompletion.c \ diff --git a/glib/gbsearcharray.c b/glib/gbsearcharray.c deleted file mode 100644 index 3b50bdecd..000000000 --- a/glib/gbsearcharray.c +++ /dev/null @@ -1,208 +0,0 @@ -/* GObject - GLib Type, Object, Parameter and Signal Library - * Copyright (C) 2000-2001 Tim Janik - * - * 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 "config.h" - -#define G_IMPLEMENT_INLINES 1 -#define __G_BSEARCHARRAY_C__ -#include "gbsearcharray.h" - -#include - - -/* --- structures --- */ -static inline guint -upper_power2 (guint number) -{ -#ifdef DISABLE_MEM_POOLS - return number; -#else /* !DISABLE_MEM_POOLS */ - return number ? 1 << g_bit_storage (number - 1) : 0; -#endif /* !DISABLE_MEM_POOLS */ -} - -GBSearchArray* -g_bsearch_array_new (GBSearchConfig *bconfig) -{ - GBSearchArray *barray; - guint size; - - g_return_val_if_fail (bconfig != NULL, NULL); - - size = sizeof (GBSearchArray) + bconfig->sizeof_node; - if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2) - size = upper_power2 (size); - barray = g_malloc0 (size); - barray->n_nodes = 0; - - return barray; -} - -void -g_bsearch_array_destroy (GBSearchArray *barray, - GBSearchConfig *bconfig) -{ - g_return_if_fail (barray != NULL); - - g_free (barray); -} - -static inline GBSearchArray* -bsearch_array_insert (GBSearchArray *barray, - GBSearchConfig *bconfig, - gconstpointer key_node, - gboolean replace) -{ - gint sizeof_node; - guint8 *check; - - sizeof_node = bconfig->sizeof_node; - if (barray->n_nodes == 0) - { - guint new_size = sizeof (GBSearchArray) + sizeof_node; - - if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2) - new_size = upper_power2 (new_size); - barray = g_realloc (barray, new_size); - barray->n_nodes = 1; - check = G_BSEARCH_ARRAY_NODES (barray); - } - else - { - GBSearchCompareFunc cmp_nodes = bconfig->cmp_nodes; - guint n_nodes = barray->n_nodes; - guint8 *nodes = G_BSEARCH_ARRAY_NODES (barray); - gint cmp; - guint i; - - nodes -= sizeof_node; - do - { - i = (n_nodes + 1) >> 1; - check = nodes + i * sizeof_node; - cmp = cmp_nodes (key_node, check); - if (cmp > 0) - { - n_nodes -= i; - nodes = check; - } - else if (cmp < 0) - n_nodes = i - 1; - else /* if (cmp == 0) */ - { - if (replace) - memcpy (check, key_node, sizeof_node); - return barray; - } - } - while (n_nodes); - /* grow */ - if (cmp > 0) - check += sizeof_node; - i = (check - ((guint8*) G_BSEARCH_ARRAY_NODES (barray))) / sizeof_node; - n_nodes = barray->n_nodes++; - if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2) - { - guint new_size = upper_power2 (sizeof (GBSearchArray) + barray->n_nodes * sizeof_node); - guint old_size = upper_power2 (sizeof (GBSearchArray) + n_nodes * sizeof_node); - - if (new_size != old_size) - barray = g_realloc (barray, new_size); - } - else - barray = g_realloc (barray, sizeof (GBSearchArray) + barray->n_nodes * sizeof_node); - check = ((guint8*) G_BSEARCH_ARRAY_NODES (barray)) + i * sizeof_node; - g_memmove (check + sizeof_node, check, (n_nodes - i) * sizeof_node); - } - memcpy (check, key_node, sizeof_node); - - return barray; -} - -GBSearchArray* -g_bsearch_array_insert (GBSearchArray *barray, - GBSearchConfig *bconfig, - gconstpointer key_node, - gboolean replace_existing) -{ - g_return_val_if_fail (barray != NULL, NULL); - g_return_val_if_fail (bconfig != NULL, barray); - g_return_val_if_fail (key_node != NULL, barray); - - return bsearch_array_insert (barray, bconfig, key_node, replace_existing); -} - -GBSearchArray* -g_bsearch_array_remove_node (GBSearchArray *barray, - GBSearchConfig *bconfig, - gpointer _node_in_array) -{ - guint8 *nodes, *bound, *node_in_array = _node_in_array; - guint old_size; - - g_return_val_if_fail (barray != NULL, NULL); - g_return_val_if_fail (bconfig != NULL, barray); - - nodes = G_BSEARCH_ARRAY_NODES (barray); - old_size = bconfig->sizeof_node; - old_size *= barray->n_nodes; /* beware of int widths */ - bound = nodes + old_size; - - g_return_val_if_fail (node_in_array >= nodes && node_in_array < bound, barray); - - bound -= bconfig->sizeof_node; - barray->n_nodes -= 1; - g_memmove (node_in_array, node_in_array + bconfig->sizeof_node, (bound - node_in_array) / bconfig->sizeof_node); - - if ((bconfig->flags & G_BSEARCH_ARRAY_DEFER_SHRINK) == 0) - { - guint new_size = bound - nodes; /* old_size - bconfig->sizeof_node */ - - if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2) - { - new_size = upper_power2 (sizeof (GBSearchArray) + new_size); - old_size = upper_power2 (sizeof (GBSearchArray) + old_size); - if (old_size != new_size) - barray = g_realloc (barray, new_size); - } - else - barray = g_realloc (barray, sizeof (GBSearchArray) + new_size); - } - return barray; -} - -GBSearchArray* -g_bsearch_array_remove (GBSearchArray *barray, - GBSearchConfig *bconfig, - gconstpointer key_node) -{ - gpointer node_in_array; - - g_return_val_if_fail (barray != NULL, NULL); - g_return_val_if_fail (bconfig != NULL, barray); - - node_in_array = g_bsearch_array_lookup (barray, bconfig, key_node); - if (!node_in_array) - { - g_warning (G_STRLOC ": unable to remove unexistant node"); - return barray; - } - else - return g_bsearch_array_remove_node (barray, bconfig, node_in_array); -} diff --git a/glib/gbsearcharray.h b/glib/gbsearcharray.h index f7c443aab..858a4a4a4 100644 --- a/glib/gbsearcharray.h +++ b/glib/gbsearcharray.h @@ -1,166 +1,303 @@ -/* GObject - GLib Type, Object, Parameter and Signal Library - * Copyright (C) 2000-2001 Tim Janik +/* GBSearchArray - Binary Searchable Array implementation + * Copyright (C) 2000-2003 Tim Janik * - * 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 software is provided "as is"; redistribution and modification + * is permitted, provided that the following disclaimer is retained. * - * This library is distributed in the hope that it will be useful, + * This software 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. - * - * gbsearcharray.h: binary searchable sorted array maintenance + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * In no event shall the authors or contributors be liable for any + * direct, indirect, incidental, special, exemplary, or consequential + * damages (including, but not limited to, procurement of substitute + * goods or services; loss of use, data, or profits; or business + * interruption) however caused and on any theory of liability, whether + * in contract, strict liability, or tort (including negligence or + * otherwise) arising in any way out of the use of this software, even + * if advised of the possibility of such damage. */ #ifndef __G_BSEARCH_ARRAY_H__ #define __G_BSEARCH_ARRAY_H__ -#include -#include -#include -#include +#include +#include -G_BEGIN_DECLS -/* helper macro to avoid signed overflow for value comparisions */ -#define G_BSEARCH_ARRAY_CMP(v1,v2) ((v1) < (v2) ? -1 : (v1) > (v2)) +G_BEGIN_DECLS /* c++ guards */ + +/* this implementation is intended to be usable in third-party code + * simply by pasting the contents of this file. as such, the + * implementation needs to be self-contained within this file. + */ + +/* convenience macro to avoid signed overflow for value comparisions */ +#define G_BSEARCH_ARRAY_CMP(v1,v2) ((v1) > (v2) ? +1 : (v1) == (v2) ? 0 : -1) /* --- typedefs --- */ -typedef union _GBSearchArray GBSearchArray; -typedef struct _GBSearchConfig GBSearchConfig; -typedef gint (*GBSearchCompareFunc) (gconstpointer bsearch_node1, - gconstpointer bsearch_node2); +typedef gint (*GBSearchCompareFunc) (gconstpointer bsearch_node1, /* key */ + gconstpointer bsearch_node2); typedef enum { - G_BSEARCH_ARRAY_ALIGN_POWER2 = 1 << 0, - G_BSEARCH_ARRAY_DEFER_SHRINK = 1 << 1 + G_BSEARCH_ARRAY_ALIGN_POWER2 = 1 << 0, /* align memory to power2 sizes */ + G_BSEARCH_ARRAY_AUTO_SHRINK = 1 << 1 /* shrink array upon removal */ } GBSearchArrayFlags; /* --- structures --- */ -struct _GBSearchConfig +typedef struct { - guint16 sizeof_node; + guint sizeof_node; GBSearchCompareFunc cmp_nodes; - guint16 flags; -}; -union _GBSearchArray + guint flags; +} GBSearchConfig; +typedef union { guint n_nodes; + /*< private >*/ gpointer alignment_dummy1; glong alignment_dummy2; gdouble alignment_dummy3; -}; +} GBSearchArray; -/* --- prototypes --- */ -GBSearchArray* g_bsearch_array_new (GBSearchConfig *bconfig); -void g_bsearch_array_destroy (GBSearchArray *barray, - GBSearchConfig *bconfig); -GBSearchArray* g_bsearch_array_insert (GBSearchArray *barray, - GBSearchConfig *bconfig, - gconstpointer key_node, - gboolean replace_existing); -GBSearchArray* g_bsearch_array_remove (GBSearchArray *barray, - GBSearchConfig *bconfig, - gconstpointer key_node); -GBSearchArray* g_bsearch_array_remove_node (GBSearchArray *barray, - GBSearchConfig *bconfig, - gpointer node_in_array); -G_INLINE_FUNC -gpointer g_bsearch_array_lookup (GBSearchArray *barray, - GBSearchConfig *bconfig, - gconstpointer key_node); -G_INLINE_FUNC -gpointer g_bsearch_array_get_nth (GBSearchArray *barray, - GBSearchConfig *bconfig, - guint n); -G_INLINE_FUNC -guint g_bsearch_array_get_index (GBSearchArray *barray, - GBSearchConfig *bconfig, - gpointer node_in_array); +/* --- public API --- */ +static inline GBSearchArray* g_bsearch_array_create (const GBSearchConfig *bconfig); +static inline gpointer g_bsearch_array_get_nth (GBSearchArray *barray, + const GBSearchConfig *bconfig, + guint nth); +static inline guint g_bsearch_array_get_index (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer node_in_array); +static inline GBSearchArray* g_bsearch_array_remove (GBSearchArray *barray, + const GBSearchConfig *bconfig, + guint index); +/* provide uninitialized space at index for node insertion */ +static inline GBSearchArray* g_bsearch_array_grow (GBSearchArray *barray, + const GBSearchConfig *bconfig, + guint index); +/* insert key_node into array if it does not exist, otherwise do nothing */ +static inline GBSearchArray* g_bsearch_array_insert (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer key_node); +/* insert key_node into array if it does not exist, + * otherwise replace the existing node's contents with key_node + */ +static inline GBSearchArray* g_bsearch_array_replace (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer key_node); +static inline void g_bsearch_array_free (GBSearchArray *barray, + const GBSearchConfig *bconfig); +#define g_bsearch_array_get_n_nodes(barray) (((GBSearchArray*) (barray))->n_nodes) + +/* g_bsearch_array_lookup(): + * return NULL or exact match node + */ +#define g_bsearch_array_lookup(barray, bconfig, key_node) \ + g_bsearch_array_lookup_fuzzy ((barray), (bconfig), (key_node), 0) + +/* g_bsearch_array_lookup_sibling(): + * return NULL for barray->n_nodes==0, otherwise return the + * exact match node, or, if there's no such node, return the + * node last visited, which is pretty close to an exact match + * (will be one off into either direction). + */ +#define g_bsearch_array_lookup_sibling(barray, bconfig, key_node) \ + g_bsearch_array_lookup_fuzzy ((barray), (bconfig), (key_node), 1) + +/* g_bsearch_array_lookup_insertion(): + * return NULL for barray->n_nodes==0 or exact match, otherwise + * return the node where key_node should be inserted (may be one + * after end, i.e. g_bsearch_array_get_index(result) <= barray->n_nodes). + */ +#define g_bsearch_array_lookup_insertion(barray, bconfig, key_node) \ + g_bsearch_array_lookup_fuzzy ((barray), (bconfig), (key_node), 2) -/* initialization of static arrays */ -#define G_STATIC_BCONFIG(sizeof_node, cmp_nodes, flags) \ - { (sizeof_node), (cmp_nodes), (flags), } - - -/* --- implementation details --- */ -#define G_BSEARCH_ARRAY_NODES(barray) ((gpointer) (((guint8*) (barray)) + sizeof (GBSearchArray))) -#if defined (G_CAN_INLINE) || defined (__G_BSEARCHARRAY_C__) -G_INLINE_FUNC gpointer -g_bsearch_array_lookup (GBSearchArray *barray, - GBSearchConfig *bconfig, - gconstpointer key_node) +/* --- implementation --- */ +/* helper macro to cut down realloc()s */ +#ifdef DISABLE_MEM_POOLS +#define G_BSEARCH_UPPER_POWER2(n) (n) +#else /* !DISABLE_MEM_POOLS */ +#define G_BSEARCH_UPPER_POWER2(n) ((n) ? 1 << g_bit_storage ((n) - 1) : 0) +#endif /* !DISABLE_MEM_POOLS */ +#define G_BSEARCH_ARRAY_NODES(barray) (((guint8*) (barray)) + sizeof (GBSearchArray)) +static inline GBSearchArray* +g_bsearch_array_create (const GBSearchConfig *bconfig) { - if (barray->n_nodes > 0) - { - GBSearchCompareFunc cmp_nodes = bconfig->cmp_nodes; - gint sizeof_node = bconfig->sizeof_node; - guint n_nodes = barray->n_nodes; - guint8 *nodes = G_BSEARCH_ARRAY_NODES (barray); + GBSearchArray *barray; + guint size; - nodes -= sizeof_node; - do - { - guint8 *check; - guint i; - register gint cmp; - - i = (n_nodes + 1) >> 1; - check = nodes + i * sizeof_node; - cmp = cmp_nodes (key_node, check); - if (cmp == 0) - return check; - else if (cmp > 0) - { - n_nodes -= i; - nodes = check; - } - else /* if (cmp < 0) */ - n_nodes = i - 1; - } - while (n_nodes); - } - - return NULL; + g_return_val_if_fail (bconfig != NULL, NULL); + + size = sizeof (GBSearchArray) + bconfig->sizeof_node; + if (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2) + size = G_BSEARCH_UPPER_POWER2 (size); + barray = g_realloc (NULL, size); + memset (barray, 0, sizeof (GBSearchArray)); + + return barray; } -G_INLINE_FUNC gpointer -g_bsearch_array_get_nth (GBSearchArray *barray, - GBSearchConfig *bconfig, - guint n) +static inline gpointer +g_bsearch_array_lookup_fuzzy (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer key_node, + const guint sibling_or_after); +static inline gpointer +g_bsearch_array_lookup_fuzzy (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer key_node, + const guint sibling_or_after) { - if (n < barray->n_nodes) - { - guint8 *nodes = (guint8*) G_BSEARCH_ARRAY_NODES (barray); + GBSearchCompareFunc cmp_nodes = bconfig->cmp_nodes; + guint8 *check = NULL, *nodes = G_BSEARCH_ARRAY_NODES (barray); + guint n_nodes = barray->n_nodes, offs = 0; + guint sizeof_node = bconfig->sizeof_node; + gint cmp = 0; - return nodes + n * bconfig->sizeof_node; + while (offs < n_nodes) + { + guint i = (offs + n_nodes) >> 1; + + check = nodes + i * sizeof_node; + cmp = cmp_nodes (key_node, check); + if (cmp == 0) + return sibling_or_after > 1 ? NULL : check; + else if (cmp < 0) + n_nodes = i; + else /* (cmp > 0) */ + offs = i + 1; } - else - return NULL; + + /* check is last mismatch, cmp > 0 indicates greater key */ + return G_LIKELY (!sibling_or_after) ? NULL : (sibling_or_after > 1 && cmp > 0) ? check + sizeof_node : check; } -G_INLINE_FUNC -guint -g_bsearch_array_get_index (GBSearchArray *barray, - GBSearchConfig *bconfig, - gpointer node_in_array) +static inline gpointer +g_bsearch_array_get_nth (GBSearchArray *barray, + const GBSearchConfig *bconfig, + guint nth) { - guint distance = ((guint8*) node_in_array) - ((guint8*) G_BSEARCH_ARRAY_NODES (barray)); + return (G_LIKELY (nth < barray->n_nodes) ? + G_BSEARCH_ARRAY_NODES (barray) + nth * bconfig->sizeof_node : + NULL); +} +static inline guint +g_bsearch_array_get_index (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer node_in_array) +{ + guint distance = ((guint8*) node_in_array) - G_BSEARCH_ARRAY_NODES (barray); + + g_return_val_if_fail (node_in_array != NULL, barray->n_nodes); distance /= bconfig->sizeof_node; - return MIN (distance, barray->n_nodes); + return MIN (distance, barray->n_nodes + 1); /* may return one after end */ } -#endif /* G_CAN_INLINE || __G_BSEARCHARRAY_C__ */ +static inline GBSearchArray* +g_bsearch_array_grow (GBSearchArray *barray, + const GBSearchConfig *bconfig, + guint index) +{ + guint old_size = barray->n_nodes * bconfig->sizeof_node; + guint new_size = old_size + bconfig->sizeof_node; + guint8 *node; -G_END_DECLS + g_return_val_if_fail (index <= barray->n_nodes, NULL); -#endif /* __G_BSEARCH_ARRAY_H__ */ + if (G_UNLIKELY (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2)) + { + new_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + new_size); + old_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + old_size); + if (old_size != new_size) + barray = g_realloc (barray, new_size); + } + else + barray = g_realloc (barray, sizeof (GBSearchArray) + new_size); + node = G_BSEARCH_ARRAY_NODES (barray) + index * bconfig->sizeof_node; + g_memmove (node + bconfig->sizeof_node, node, (barray->n_nodes - index) * bconfig->sizeof_node); + barray->n_nodes += 1; + return barray; +} +static inline GBSearchArray* +g_bsearch_array_insert (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer key_node) +{ + guint8 *node; + + if (G_UNLIKELY (!barray->n_nodes)) + { + barray = g_bsearch_array_grow (barray, bconfig, 0); + node = G_BSEARCH_ARRAY_NODES (barray); + } + else + { + node = g_bsearch_array_lookup_insertion (barray, bconfig, key_node); + if (G_LIKELY (node)) + { + guint index = g_bsearch_array_get_index (barray, bconfig, node); + + /* grow and insert */ + barray = g_bsearch_array_grow (barray, bconfig, index); + node = G_BSEARCH_ARRAY_NODES (barray) + index * bconfig->sizeof_node; + } + else /* no insertion needed, node already there */ + return barray; + } + memcpy (node, key_node, bconfig->sizeof_node); + return barray; +} +static inline GBSearchArray* +g_bsearch_array_replace (GBSearchArray *barray, + const GBSearchConfig *bconfig, + gconstpointer key_node) +{ + guint8 *node = g_bsearch_array_lookup (barray, bconfig, key_node); + if (G_LIKELY (node)) /* expected path */ + memcpy (node, key_node, bconfig->sizeof_node); + else /* revert to insertion */ + barray = g_bsearch_array_insert (barray, bconfig, key_node); + return barray; +} +static inline GBSearchArray* +g_bsearch_array_remove (GBSearchArray *barray, + const GBSearchConfig *bconfig, + guint index) +{ + guint8 *node; + + g_return_val_if_fail (index < barray->n_nodes, NULL); + + barray->n_nodes -= 1; + node = G_BSEARCH_ARRAY_NODES (barray) + index * bconfig->sizeof_node; + g_memmove (node, node + bconfig->sizeof_node, (barray->n_nodes - index) * bconfig->sizeof_node); + if (G_UNLIKELY (bconfig->flags & G_BSEARCH_ARRAY_AUTO_SHRINK)) + { + guint new_size = barray->n_nodes * bconfig->sizeof_node; + guint old_size = new_size + bconfig->sizeof_node; + + if (G_UNLIKELY (bconfig->flags & G_BSEARCH_ARRAY_ALIGN_POWER2)) + { + new_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + new_size); + old_size = G_BSEARCH_UPPER_POWER2 (sizeof (GBSearchArray) + old_size); + if (old_size != new_size) + barray = g_realloc (barray, new_size); + } + else + barray = g_realloc (barray, sizeof (GBSearchArray) + new_size); + } + return barray; +} +static inline void +g_bsearch_array_free (GBSearchArray *barray, + const GBSearchConfig *bconfig) +{ + g_return_if_fail (barray != NULL); + + g_free (barray); +} + +G_END_DECLS /* c++ guards */ + +#endif /* !__G_BSEARCH_ARRAY_H__ */