From c3ecca225cd1f13f75250d35e5356ee5f433cff2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 23 Sep 2016 13:37:22 +0200 Subject: [PATCH] core: add _nm_utils_array_find_binary_search() Also add nm_cmp_uint32_p_with_data(). Will be used later. --- libnm-core/nm-core-internal.h | 1 + libnm-core/nm-utils.c | 34 +++++++++++++++++++++++ libnm-core/tests/test-general.c | 41 ++++++++++++++++++++++++++++ shared/nm-utils/nm-macros-internal.h | 13 +++++++++ 4 files changed, 89 insertions(+) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 111b26d588..471353e741 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -147,6 +147,7 @@ GPtrArray *_nm_utils_copy_object_array (const GPtrArray *array); gssize _nm_utils_ptrarray_find_first (gconstpointer *list, gssize len, gconstpointer needle); gssize _nm_utils_ptrarray_find_binary_search (gconstpointer *list, gsize len, gconstpointer needle, GCompareDataFunc cmpfcn, gpointer user_data); +gssize _nm_utils_array_find_binary_search (gconstpointer list, gsize elem_size, gsize len, gconstpointer needle, GCompareDataFunc cmpfcn, gpointer user_data); gssize _nm_utils_strv_find_first (char **list, gssize len, const char *needle); diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index c55e4ba81f..818b0c43ec 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -724,6 +724,40 @@ _nm_utils_ptrarray_find_binary_search (gconstpointer *list, gsize len, gconstpoi return ~imin; } +gssize +_nm_utils_array_find_binary_search (gconstpointer list, gsize elem_size, gsize len, gconstpointer needle, GCompareDataFunc cmpfcn, gpointer user_data) +{ + gssize imin, imax, imid; + int cmp; + + g_return_val_if_fail (list || !len, ~((gssize) 0)); + g_return_val_if_fail (cmpfcn, ~((gssize) 0)); + g_return_val_if_fail (elem_size > 0, ~((gssize) 0)); + + imin = 0; + if (len == 0) + return ~imin; + + imax = len - 1; + + while (imin <= imax) { + imid = imin + (imax - imin) / 2; + + cmp = cmpfcn (&((const char *) list)[elem_size * imid], needle, user_data); + if (cmp == 0) + return imid; + + if (cmp < 0) + imin = imid + 1; + else + imax = imid - 1; + } + + /* return the inverse of @imin. This is a negative number, but + * also is ~imin the position where the value should be inserted. */ + return ~imin; +} + GVariant * _nm_utils_bytes_to_dbus (const GValue *prop_value) { diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 8d5997ad2c..e71dd8bc56 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -5006,10 +5006,51 @@ _test_find_binary_search_do (const int *array, gsize len) } } } + +static void +_test_find_binary_search_do_uint32 (const int *int_array, gsize len) +{ + gssize idx; + const int OFFSET = 100; + const int NEEDLE = 0 + OFFSET; + gssize expected_result = -1; + guint32 array[len]; + + /* the test data has negative values. Shift them... */ + for (idx = 0; idx < len; idx++) { + int v = int_array[idx]; + + g_assert (v > -OFFSET); + g_assert (v < OFFSET); + g_assert (idx == 0 || v > int_array[idx - 1]); + array[idx] = (guint32) (int_array[idx] + OFFSET); + if (array[idx] == NEEDLE) + expected_result = idx; + } + + idx = _nm_utils_array_find_binary_search (array, + sizeof (guint32), + len, + &NEEDLE, + nm_cmp_uint32_p_with_data, + NULL); + if (expected_result >= 0) + g_assert_cmpint (expected_result, ==, idx); + else { + gssize idx2 = ~idx; + g_assert_cmpint (idx, <, 0); + + g_assert (idx2 >= 0); + g_assert (idx2 <= len); + g_assert (idx2 - 1 < 0 || array[idx2 - 1] < NEEDLE); + g_assert (idx2 >= len || array[idx2] > NEEDLE); + } +} #define test_find_binary_search_do(...) \ G_STMT_START { \ const int _array[] = { __VA_ARGS__ }; \ _test_find_binary_search_do (_array, G_N_ELEMENTS (_array)); \ + _test_find_binary_search_do_uint32 (_array, G_N_ELEMENTS (_array)); \ } G_STMT_END static void diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 9e9f5d8f3c..003a9e974f 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -516,6 +516,19 @@ nm_strcmp_p_with_data (gconstpointer a, gconstpointer b, gpointer user_data) return strcmp (s1, s2); } +static inline int +nm_cmp_uint32_p_with_data (gconstpointer p_a, gconstpointer p_b, gpointer user_data) +{ + const guint32 a = *((const guint32 *) p_a); + const guint32 b = *((const guint32 *) p_b); + + if (a < b) + return -1; + if (a > b) + return 1; + return 0; +} + /*****************************************************************************/ /* Taken from systemd's UNIQ_T and UNIQ macros. */