core: add _nm_utils_array_find_binary_search()

Also add nm_cmp_uint32_p_with_data(). Will be used later.
This commit is contained in:
Thomas Haller 2016-09-23 13:37:22 +02:00
parent 08f5681b0e
commit c3ecca225c
4 changed files with 89 additions and 0 deletions

View file

@ -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);

View file

@ -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)
{

View file

@ -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

View file

@ -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. */