mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 22:52:09 +01:00
Merge branch 'garray_binary_search' into 'master'
Add g_array_binary_search() to garray API Closes #373 See merge request GNOME/glib!850
This commit is contained in:
commit
c23ee5fabf
@ -2626,6 +2626,7 @@ g_array_remove_index_fast
|
|||||||
g_array_remove_range
|
g_array_remove_range
|
||||||
g_array_sort
|
g_array_sort
|
||||||
g_array_sort_with_data
|
g_array_sort_with_data
|
||||||
|
g_array_binary_search
|
||||||
g_array_index
|
g_array_index
|
||||||
g_array_set_size
|
g_array_set_size
|
||||||
g_array_set_clear_func
|
g_array_set_clear_func
|
||||||
|
@ -785,6 +785,87 @@ g_array_sort_with_data (GArray *farray,
|
|||||||
user_data);
|
user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_array_binary_search:
|
||||||
|
* @array: a #GArray.
|
||||||
|
* @target: a pointer to the item to look up.
|
||||||
|
* @compare_func: A #GCompareFunc used to locate @target.
|
||||||
|
* @out_match_index: (optional) (out caller-allocates): return location
|
||||||
|
* for the index of the element, if found.
|
||||||
|
*
|
||||||
|
* Checks whether @target exists in @array by performing a binary
|
||||||
|
* search based on the given comparison function @compare_func which
|
||||||
|
* get pointers to items as arguments. If the element is found, %TRUE
|
||||||
|
* is returned and the element’s index is returned in @out_match_index
|
||||||
|
* (if non-%NULL). Otherwise, %FALSE is returned and @out_match_index
|
||||||
|
* is undefined. If @target exists multiple times in @array, the index
|
||||||
|
* of the first instance is returned. This search is using a binary
|
||||||
|
* search, so the @array must absolutely be sorted to return a correct
|
||||||
|
* result (if not, the function may produce false-negative).
|
||||||
|
*
|
||||||
|
* This example defines a comparison function and search an element in a #GArray:
|
||||||
|
* |[<!-- language="C" -->
|
||||||
|
* static gint*
|
||||||
|
* cmpint (gconstpointer a, gconstpointer b)
|
||||||
|
* {
|
||||||
|
* const gint *_a = a;
|
||||||
|
* const gint *_b = b;
|
||||||
|
*
|
||||||
|
* return *_a - *_b;
|
||||||
|
* }
|
||||||
|
* ...
|
||||||
|
* gint i = 424242;
|
||||||
|
* guint matched_index;
|
||||||
|
* gboolean result = g_array_binary_search (garray, &i, cmpint, &matched_index);
|
||||||
|
* ...
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if @target is one of the elements of @array, %FALSE otherwise.
|
||||||
|
*
|
||||||
|
* Since: 2.62
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
g_array_binary_search (GArray *array,
|
||||||
|
gconstpointer target,
|
||||||
|
GCompareFunc compare_func,
|
||||||
|
guint *out_match_index)
|
||||||
|
{
|
||||||
|
gboolean result = FALSE;
|
||||||
|
GRealArray *_array = (GRealArray *) array;
|
||||||
|
guint left, middle, right;
|
||||||
|
gint val;
|
||||||
|
|
||||||
|
g_return_val_if_fail (_array != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (compare_func != NULL, FALSE);
|
||||||
|
|
||||||
|
if (G_LIKELY(_array->len))
|
||||||
|
{
|
||||||
|
left = 0;
|
||||||
|
right = _array->len - 1;
|
||||||
|
|
||||||
|
while (left <= right)
|
||||||
|
{
|
||||||
|
middle = (left + right) / 2;
|
||||||
|
|
||||||
|
val = compare_func (_array->data + (_array->elt_size * middle), target);
|
||||||
|
if (val < 0)
|
||||||
|
left = middle + 1;
|
||||||
|
else if (val > 0)
|
||||||
|
right = middle - 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result && out_match_index != NULL)
|
||||||
|
*out_match_index = middle;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns the smallest power of 2 greater than n, or n if
|
/* Returns the smallest power of 2 greater than n, or n if
|
||||||
* such power does not fit in a guint
|
* such power does not fit in a guint
|
||||||
*/
|
*/
|
||||||
|
@ -119,6 +119,11 @@ GLIB_AVAILABLE_IN_ALL
|
|||||||
void g_array_sort_with_data (GArray *array,
|
void g_array_sort_with_data (GArray *array,
|
||||||
GCompareDataFunc compare_func,
|
GCompareDataFunc compare_func,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
GLIB_AVAILABLE_IN_2_62
|
||||||
|
gboolean g_array_binary_search (GArray *array,
|
||||||
|
gconstpointer target,
|
||||||
|
GCompareFunc compare_func,
|
||||||
|
guint *out_match_index);
|
||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
void g_array_set_clear_func (GArray *array,
|
void g_array_set_clear_func (GArray *array,
|
||||||
GDestroyNotify clear_func);
|
GDestroyNotify clear_func);
|
||||||
|
@ -628,6 +628,108 @@ array_clear_func (void)
|
|||||||
g_assert_cmpint (num_clear_func_invocations, ==, 10);
|
g_assert_cmpint (num_clear_func_invocations, ==, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Defining a comparison function for testing g_array_binary_search() */
|
||||||
|
static gint
|
||||||
|
cmpint (gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
const gint *_a = a;
|
||||||
|
const gint *_b = b;
|
||||||
|
|
||||||
|
return *_a - *_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Testing g_array_binary_search() function */
|
||||||
|
static void
|
||||||
|
test_array_binary_search (void)
|
||||||
|
{
|
||||||
|
GArray *garray;
|
||||||
|
guint i, matched_index;
|
||||||
|
|
||||||
|
if (g_test_undefined ())
|
||||||
|
{
|
||||||
|
/* Testing degenerated cases */
|
||||||
|
garray = g_array_sized_new (FALSE, FALSE, sizeof (guint), 0);
|
||||||
|
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||||
|
"*assertion*!= NULL*");
|
||||||
|
g_assert_false (g_array_binary_search (NULL, &i, cmpint, NULL));
|
||||||
|
g_test_assert_expected_messages ();
|
||||||
|
|
||||||
|
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||||
|
"*assertion*!= NULL*");
|
||||||
|
g_assert_false (g_array_binary_search (garray, &i, NULL, NULL));
|
||||||
|
g_test_assert_expected_messages ();
|
||||||
|
g_array_free (garray, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Testing array of size 0 */
|
||||||
|
garray = g_array_sized_new (FALSE, FALSE, sizeof (guint), 0);
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
g_assert_false (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
g_array_free (garray, TRUE);
|
||||||
|
|
||||||
|
/* Testing array of size 1 */
|
||||||
|
garray = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1);
|
||||||
|
i = 1;
|
||||||
|
g_array_append_val (garray, i);
|
||||||
|
|
||||||
|
g_assert_true (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
i = 2;
|
||||||
|
g_assert_false (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
g_array_free (garray, TRUE);
|
||||||
|
|
||||||
|
/* Testing array of size 2 */
|
||||||
|
garray = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2);
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
g_array_append_val (garray, i);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
g_assert_true (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
i = 3;
|
||||||
|
g_assert_false (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
g_array_free (garray, TRUE);
|
||||||
|
|
||||||
|
/* Testing array of size 3 */
|
||||||
|
garray = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3);
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
g_array_append_val (garray, i);
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
g_assert_true (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
i = 4;
|
||||||
|
g_assert_false (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
g_array_free (garray, TRUE);
|
||||||
|
|
||||||
|
/* Testing array of size 10000 */
|
||||||
|
garray = g_array_sized_new (FALSE, FALSE, sizeof (guint), 10000);
|
||||||
|
|
||||||
|
for (i = 0; i < 10000; i++)
|
||||||
|
g_array_append_val (garray, i);
|
||||||
|
|
||||||
|
for (i = 0; i < 10000; i++)
|
||||||
|
g_assert_true (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
|
||||||
|
for (i = 0; i < 10000; i++)
|
||||||
|
{
|
||||||
|
g_assert_true (g_array_binary_search (garray, &i, cmpint, &matched_index));
|
||||||
|
g_assert_cmpint (i, ==, matched_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Testing negative result */
|
||||||
|
i = 10001;
|
||||||
|
g_assert_false (g_array_binary_search (garray, &i, cmpint, NULL));
|
||||||
|
g_assert_false (g_array_binary_search (garray, &i, cmpint, &matched_index));
|
||||||
|
|
||||||
|
g_array_free (garray, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pointer_array_add (void)
|
pointer_array_add (void)
|
||||||
{
|
{
|
||||||
@ -1546,6 +1648,7 @@ main (int argc, char *argv[])
|
|||||||
g_test_add_func ("/array/new/zero-terminated", array_new_zero_terminated);
|
g_test_add_func ("/array/new/zero-terminated", array_new_zero_terminated);
|
||||||
g_test_add_func ("/array/ref-count", array_ref_count);
|
g_test_add_func ("/array/ref-count", array_ref_count);
|
||||||
g_test_add_func ("/array/clear-func", array_clear_func);
|
g_test_add_func ("/array/clear-func", array_clear_func);
|
||||||
|
g_test_add_func ("/array/binary-search", test_array_binary_search);
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (array_configurations); i++)
|
for (i = 0; i < G_N_ELEMENTS (array_configurations); i++)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user