mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
API: Add gst_util_array_binary_search() for binary searchs on a sorted array
This will be mostly useful in all elements that have some kind of internal seek/index table. Currently almost all of them (or even all of them) are using a linear search although the used array is already sorted, wasting some CPU time without good reason. Fixes bug #573623.
This commit is contained in:
parent
a29773e4cc
commit
3c6448c64e
6 changed files with 216 additions and 0 deletions
|
@ -2363,10 +2363,14 @@ gst_util_seqnum_compare
|
||||||
gst_util_set_object_arg
|
gst_util_set_object_arg
|
||||||
gst_util_set_value_from_string
|
gst_util_set_value_from_string
|
||||||
gst_util_get_timestamp
|
gst_util_get_timestamp
|
||||||
|
GstSearchMode
|
||||||
|
gst_util_array_binary_search
|
||||||
<SUBSECTION Private>
|
<SUBSECTION Private>
|
||||||
GST_HAVE_UNALIGNED_ACCESS
|
GST_HAVE_UNALIGNED_ACCESS
|
||||||
gst_util_guint64_to_gdouble
|
gst_util_guint64_to_gdouble
|
||||||
gst_util_gdouble_to_guint64
|
gst_util_gdouble_to_guint64
|
||||||
|
GST_TYPE_SEARCH_MODE
|
||||||
|
gst_search_mode_get_type
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
|
|
@ -1073,6 +1073,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
|
||||||
g_type_class_ref (gst_uri_type_get_type ());
|
g_type_class_ref (gst_uri_type_get_type ());
|
||||||
g_type_class_ref (gst_parse_error_get_type ());
|
g_type_class_ref (gst_parse_error_get_type ());
|
||||||
g_type_class_ref (gst_parse_flags_get_type ());
|
g_type_class_ref (gst_parse_flags_get_type ());
|
||||||
|
g_type_class_ref (gst_search_mode_get_type ());
|
||||||
|
|
||||||
gst_structure_get_type ();
|
gst_structure_get_type ();
|
||||||
_gst_value_initialize ();
|
_gst_value_initialize ();
|
||||||
|
|
|
@ -3624,3 +3624,91 @@ gst_util_get_timestamp (void)
|
||||||
return GST_TIMEVAL_TO_TIME (now);
|
return GST_TIMEVAL_TO_TIME (now);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_util_array_binary_search:
|
||||||
|
* @array: the sorted input array
|
||||||
|
* @num_elements: number of elements in the array
|
||||||
|
* @element_size: size of every element in bytes
|
||||||
|
* @search_func: function to compare two elements, @search_data will always be passed as second argument
|
||||||
|
* @mode: search mode that should be used
|
||||||
|
* @search_data: element that should be found
|
||||||
|
* @user_data: data to pass to @search_func
|
||||||
|
*
|
||||||
|
* Searches inside @array for @search_data by using the comparison function
|
||||||
|
* @search_func. @array must be sorted ascending.
|
||||||
|
*
|
||||||
|
* As @search_data is always passed as second argument to @search_func it's
|
||||||
|
* not required that @search_data has the same type as the array elements.
|
||||||
|
*
|
||||||
|
* The complexity of this search function is O(log (num_elements)).
|
||||||
|
*
|
||||||
|
* Returns: The address of the found element or %NULL if nothing was found
|
||||||
|
*
|
||||||
|
* Since: 0.10.23
|
||||||
|
*/
|
||||||
|
gpointer
|
||||||
|
gst_util_array_binary_search (gpointer array, guint num_elements,
|
||||||
|
gsize element_size, GCompareDataFunc search_func, GstSearchMode mode,
|
||||||
|
gconstpointer search_data, gpointer user_data)
|
||||||
|
{
|
||||||
|
glong left = 0, right = num_elements - 1, m;
|
||||||
|
gint ret;
|
||||||
|
guint8 *data = (guint8 *) array;
|
||||||
|
|
||||||
|
g_return_val_if_fail (array != NULL, NULL);
|
||||||
|
g_return_val_if_fail (element_size > 0, NULL);
|
||||||
|
g_return_val_if_fail (search_func != NULL, NULL);
|
||||||
|
|
||||||
|
/* 0. No elements => return NULL */
|
||||||
|
if (num_elements == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* 1. If search_data is before the 0th element return the 0th element */
|
||||||
|
ret = search_func (data, search_data, user_data);
|
||||||
|
if ((ret >= 0 && mode == GST_SEARCH_MODE_AFTER) || ret == 0)
|
||||||
|
return data;
|
||||||
|
else if (ret > 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* 2. If search_data is after the last element return the last element */
|
||||||
|
ret =
|
||||||
|
search_func (data + (num_elements - 1) * element_size, search_data,
|
||||||
|
user_data);
|
||||||
|
if ((ret <= 0 && mode == GST_SEARCH_MODE_BEFORE) || ret == 0)
|
||||||
|
return data + (num_elements - 1) * element_size;
|
||||||
|
else if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* 3. else binary search */
|
||||||
|
while (TRUE) {
|
||||||
|
m = left + (right - left) / 2;
|
||||||
|
|
||||||
|
ret = search_func (data + m * element_size, search_data, user_data);
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
return data + m * element_size;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
left = m + 1;
|
||||||
|
} else {
|
||||||
|
right = m - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No exact match found */
|
||||||
|
if (right < left) {
|
||||||
|
if (mode == GST_SEARCH_MODE_EXACT) {
|
||||||
|
return NULL;
|
||||||
|
} else if (mode == GST_SEARCH_MODE_AFTER) {
|
||||||
|
if (ret < 0)
|
||||||
|
return (m < num_elements) ? data + (m + 1) * element_size : NULL;
|
||||||
|
else
|
||||||
|
return data + m * element_size;
|
||||||
|
} else {
|
||||||
|
if (ret < 0)
|
||||||
|
return data + m * element_size;
|
||||||
|
else
|
||||||
|
return (m > 0) ? data + (m - 1) * element_size : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1134,6 +1134,24 @@ GstElement * gst_parse_bin_from_description_full (const gchar * b
|
||||||
|
|
||||||
GstClockTime gst_util_get_timestamp (void);
|
GstClockTime gst_util_get_timestamp (void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstSearchMode:
|
||||||
|
* @GST_SEARCH_MODE_EXACT : Only search for exact matches.
|
||||||
|
* @GST_SEARCH_MODE_BEFORE: Search for an exact match or the element just before.
|
||||||
|
* @GST_SEARCH_MODE_AFTER : Search for an exact match or the element just after.
|
||||||
|
*
|
||||||
|
* The different search modes.
|
||||||
|
*
|
||||||
|
* Since: 0.10.23
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
GST_SEARCH_MODE_EXACT = 0,
|
||||||
|
GST_SEARCH_MODE_BEFORE,
|
||||||
|
GST_SEARCH_MODE_AFTER
|
||||||
|
} GstSearchMode;
|
||||||
|
|
||||||
|
gpointer gst_util_array_binary_search (gpointer array, guint num_elements, gsize element_size, GCompareDataFunc search_func, GstSearchMode mode, gconstpointer search_data, gpointer user_data);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_UTILS_H__ */
|
#endif /* __GST_UTILS_H__ */
|
||||||
|
|
|
@ -610,6 +610,108 @@ GST_START_TEST (test_set_value_from_string)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
static gint
|
||||||
|
_binary_search_compare (guint32 * a, guint32 * b)
|
||||||
|
{
|
||||||
|
return *a - *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (test_binary_search)
|
||||||
|
{
|
||||||
|
guint32 data[257];
|
||||||
|
guint32 *match;
|
||||||
|
guint32 search_element = 121 * 2;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < 257; i++)
|
||||||
|
data[i] = (i + 1) * 2;
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_EXACT,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match != NULL);
|
||||||
|
fail_unless_equals_int (match - data, 120);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_BEFORE,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match != NULL);
|
||||||
|
fail_unless_equals_int (match - data, 120);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_AFTER,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match != NULL);
|
||||||
|
fail_unless_equals_int (match - data, 120);
|
||||||
|
|
||||||
|
search_element = 0;
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_EXACT,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match == NULL);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_AFTER,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match != NULL);
|
||||||
|
fail_unless_equals_int (match - data, 0);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_BEFORE,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match == NULL);
|
||||||
|
|
||||||
|
search_element = 1000;
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_EXACT,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match == NULL);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_AFTER,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match == NULL);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_BEFORE,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match != NULL);
|
||||||
|
fail_unless_equals_int (match - data, 256);
|
||||||
|
|
||||||
|
search_element = 121 * 2 - 1;
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_EXACT,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match == NULL);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_AFTER,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match != NULL);
|
||||||
|
fail_unless_equals_int (match - data, 120);
|
||||||
|
|
||||||
|
match =
|
||||||
|
(guint32 *) gst_util_array_binary_search (data, 257, sizeof (guint32),
|
||||||
|
(GCompareDataFunc) _binary_search_compare, GST_SEARCH_MODE_BEFORE,
|
||||||
|
&search_element, NULL);
|
||||||
|
fail_unless (match != NULL);
|
||||||
|
fail_unless_equals_int (match - data, 119);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
gst_utils_suite (void)
|
gst_utils_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -630,6 +732,7 @@ gst_utils_suite (void)
|
||||||
tcase_add_test (tc_chain, test_element_found_tags);
|
tcase_add_test (tc_chain, test_element_found_tags);
|
||||||
tcase_add_test (tc_chain, test_element_unlink);
|
tcase_add_test (tc_chain, test_element_unlink);
|
||||||
tcase_add_test (tc_chain, test_set_value_from_string);
|
tcase_add_test (tc_chain, test_set_value_from_string);
|
||||||
|
tcase_add_test (tc_chain, test_binary_search);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -784,6 +784,7 @@ EXPORTS
|
||||||
gst_registry_xml_write_cache
|
gst_registry_xml_write_cache
|
||||||
gst_resource_error_get_type
|
gst_resource_error_get_type
|
||||||
gst_resource_error_quark
|
gst_resource_error_quark
|
||||||
|
gst_search_mode_get_type
|
||||||
gst_seek_flags_get_type
|
gst_seek_flags_get_type
|
||||||
gst_seek_type_get_type
|
gst_seek_type_get_type
|
||||||
gst_segment_clip
|
gst_segment_clip
|
||||||
|
@ -970,6 +971,7 @@ EXPORTS
|
||||||
gst_uri_protocol_is_supported
|
gst_uri_protocol_is_supported
|
||||||
gst_uri_protocol_is_valid
|
gst_uri_protocol_is_valid
|
||||||
gst_uri_type_get_type
|
gst_uri_type_get_type
|
||||||
|
gst_util_array_binary_search
|
||||||
gst_util_dump_mem
|
gst_util_dump_mem
|
||||||
gst_util_gdouble_to_guint64
|
gst_util_gdouble_to_guint64
|
||||||
gst_util_get_timestamp
|
gst_util_get_timestamp
|
||||||
|
|
Loading…
Reference in a new issue