mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-22 16:26:39 +00:00
queuearray: Add sorting and sorted pushing
Adds gst_queue_array_sort for sorting and gst_queue_array_push_sorted{,struct} for pushing in a sorted order. All three functions accept a comparison GCompareDataFunc along with optional user_data to pass to it. In gst_queue_array_sort a small workaround was needed to correctly sort non-struct arrays. Like what _find() already does, we need to dereference our pointers first, to make sure we can use the same comparison functions everywhere. This is done via a small wrapper around the provided comparison function. The array can also wrap around (tail ends up 'before' the head), in which case we have to reorder the array (similar to what do_expand() does) to then be able to use an existing sorting function, like g_qsort_with_data(). Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5112>
This commit is contained in:
parent
314ffa3fb5
commit
601e31fe6e
4 changed files with 599 additions and 5 deletions
|
@ -13322,6 +13322,72 @@ it from the queue.</doc>
|
||||||
</instance-parameter>
|
</instance-parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="push_sorted" c:identifier="gst_queue_array_push_sorted" version="1.24" introspectable="0">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">Pushes @data to the queue @array, finding the correct position
|
||||||
|
by comparing @data with each array element using @func.
|
||||||
|
|
||||||
|
This has a time complexity of O(n), so depending on the size of the queue
|
||||||
|
and expected access patterns, a different data structure might be better.
|
||||||
|
|
||||||
|
Assumes that the array is already sorted. If it is not, make sure
|
||||||
|
to call gst_queue_array_sort() first.</doc>
|
||||||
|
<source-position filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<type name="none" c:type="void"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="array" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">a #GstQueueArray object</doc>
|
||||||
|
<type name="QueueArray" c:type="GstQueueArray*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
<parameter name="data" transfer-ownership="none" nullable="1" allow-none="1">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">object to push</doc>
|
||||||
|
<type name="gpointer" c:type="gpointer"/>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="func" transfer-ownership="none" closure="2">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">comparison function</doc>
|
||||||
|
<type name="GLib.CompareDataFunc" c:type="GCompareDataFunc"/>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="user_data" transfer-ownership="none" nullable="1" allow-none="1">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">data for comparison function</doc>
|
||||||
|
<type name="gpointer" c:type="gpointer"/>
|
||||||
|
</parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
|
<method name="push_sorted_struct" c:identifier="gst_queue_array_push_sorted_struct" version="1.24" introspectable="0">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">Pushes the element at address @p_struct into the queue @array
|
||||||
|
(copying the contents of a structure of the struct_size specified
|
||||||
|
when creating the queue into the array), finding the correct position
|
||||||
|
by comparing the element at @p_struct with each element in the array using @func.
|
||||||
|
|
||||||
|
This has a time complexity of O(n), so depending on the size of the queue
|
||||||
|
and expected access patterns, a different data structure might be better.
|
||||||
|
|
||||||
|
Assumes that the array is already sorted. If it is not, make sure
|
||||||
|
to call gst_queue_array_sort() first.</doc>
|
||||||
|
<source-position filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<type name="none" c:type="void"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="array" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">a #GstQueueArray object</doc>
|
||||||
|
<type name="QueueArray" c:type="GstQueueArray*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
<parameter name="p_struct" transfer-ownership="none" nullable="1" allow-none="1">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">address of element or structure to push into the queue</doc>
|
||||||
|
<type name="gpointer" c:type="gpointer"/>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="func" transfer-ownership="none" closure="2">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">comparison function</doc>
|
||||||
|
<type name="GLib.CompareDataFunc" c:type="GCompareDataFunc"/>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="user_data" transfer-ownership="none" nullable="1" allow-none="1">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">data for comparison function</doc>
|
||||||
|
<type name="gpointer" c:type="gpointer"/>
|
||||||
|
</parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
<method name="push_tail" c:identifier="gst_queue_array_push_tail" version="1.2" introspectable="0">
|
<method name="push_tail" c:identifier="gst_queue_array_push_tail" version="1.2" introspectable="0">
|
||||||
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">Pushes @data to the tail of the queue @array.</doc>
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">Pushes @data to the tail of the queue @array.</doc>
|
||||||
<source-position filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.h"/>
|
<source-position filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.h"/>
|
||||||
|
@ -13379,6 +13445,28 @@ the array element it is given, but not free the element itself.</doc>
|
||||||
</parameter>
|
</parameter>
|
||||||
</parameters>
|
</parameters>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="sort" c:identifier="gst_queue_array_sort" version="1.24" introspectable="0">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">Sorts the queue @array by comparing elements against each other using
|
||||||
|
the provided @compare_func.</doc>
|
||||||
|
<source-position filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.h"/>
|
||||||
|
<return-value transfer-ownership="none">
|
||||||
|
<type name="none" c:type="void"/>
|
||||||
|
</return-value>
|
||||||
|
<parameters>
|
||||||
|
<instance-parameter name="array" transfer-ownership="none">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">a #GstQueueArray object</doc>
|
||||||
|
<type name="QueueArray" c:type="GstQueueArray*"/>
|
||||||
|
</instance-parameter>
|
||||||
|
<parameter name="compare_func" transfer-ownership="none" closure="1">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">comparison function</doc>
|
||||||
|
<type name="GLib.CompareDataFunc" c:type="GCompareDataFunc"/>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="user_data" transfer-ownership="none" nullable="1" allow-none="1">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">data for comparison function</doc>
|
||||||
|
<type name="gpointer" c:type="gpointer"/>
|
||||||
|
</parameter>
|
||||||
|
</parameters>
|
||||||
|
</method>
|
||||||
<function name="new" c:identifier="gst_queue_array_new" version="1.2" introspectable="0">
|
<function name="new" c:identifier="gst_queue_array_new" version="1.2" introspectable="0">
|
||||||
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">Allocates a new #GstQueueArray object with an initial
|
<doc xml:space="preserve" filename="../subprojects/gstreamer/libs/gst/base/gstqueuearray.c">Allocates a new #GstQueueArray object with an initial
|
||||||
queue size of @initial_size.</doc>
|
queue size of @initial_size.</doc>
|
||||||
|
|
|
@ -37,6 +37,9 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "gstqueuearray.h"
|
#include "gstqueuearray.h"
|
||||||
|
|
||||||
|
#define gst_queue_array_idx(a, i) \
|
||||||
|
((a)->array + (((a)->head + (i)) % (a)->size) * (a)->elt_size)
|
||||||
|
|
||||||
struct _GstQueueArray
|
struct _GstQueueArray
|
||||||
{
|
{
|
||||||
/* < private > */
|
/* < private > */
|
||||||
|
@ -50,6 +53,12 @@ struct _GstQueueArray
|
||||||
GDestroyNotify clear_func;
|
GDestroyNotify clear_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GCompareDataFunc func;
|
||||||
|
gpointer user_data;
|
||||||
|
} QueueSortData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_queue_array_new_for_struct: (skip)
|
* gst_queue_array_new_for_struct: (skip)
|
||||||
* @struct_size: Size of each element (e.g. structure) in the array
|
* @struct_size: Size of each element (e.g. structure) in the array
|
||||||
|
@ -431,6 +440,212 @@ gst_queue_array_push_tail (GstQueueArray * array, gpointer data)
|
||||||
array->length++;
|
array->length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Moves all elements in the queue placed after the given position in the internal array */
|
||||||
|
static void
|
||||||
|
gst_queue_array_move_data_after_position (GstQueueArray * array, guint pos)
|
||||||
|
{
|
||||||
|
guint elt_size = array->elt_size;
|
||||||
|
|
||||||
|
/* If the array does not wrap around OR if it does, but we're inserting past that point */
|
||||||
|
if (array->head < array->tail ||
|
||||||
|
(array->head >= array->tail && pos < array->head)) {
|
||||||
|
memmove (array->array + (pos + 1) * elt_size, array->array + pos * elt_size,
|
||||||
|
(array->tail - pos) * elt_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, array wraps around and we're inserting before the breaking point.
|
||||||
|
* First, move everything past that point by one place. */
|
||||||
|
memmove (array->array + elt_size, array->array, array->tail * elt_size);
|
||||||
|
|
||||||
|
/* Then move the last element from before the wrap-around point to right after it. */
|
||||||
|
memcpy (array->array, array->array + (array->size - 1) * elt_size, elt_size);
|
||||||
|
|
||||||
|
/* If we're inserting right before the breaking point, no further action is needed.
|
||||||
|
* Otherwise, move data between insertion point and the breaking point by one place. */
|
||||||
|
if (pos != array->size - 1) {
|
||||||
|
memmove (array->array + (pos + 1) * elt_size, array->array + pos * elt_size,
|
||||||
|
(array->size - pos - 1) * elt_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_queue_array_push_sorted: (skip)
|
||||||
|
* @array: a #GstQueueArray object
|
||||||
|
* @data: object to push
|
||||||
|
* @func: comparison function
|
||||||
|
* @user_data: (nullable): data for comparison function
|
||||||
|
*
|
||||||
|
* Pushes @data to the queue @array, finding the correct position
|
||||||
|
* by comparing @data with each array element using @func.
|
||||||
|
*
|
||||||
|
* This has a time complexity of O(n), so depending on the size of the queue
|
||||||
|
* and expected access patterns, a different data structure might be better.
|
||||||
|
*
|
||||||
|
* Assumes that the array is already sorted. If it is not, make sure
|
||||||
|
* to call gst_queue_array_sort() first.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_queue_array_push_sorted (GstQueueArray * array, gpointer data,
|
||||||
|
GCompareDataFunc func, gpointer user_data)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
gpointer *p_element;
|
||||||
|
|
||||||
|
g_return_if_fail (array != NULL);
|
||||||
|
g_return_if_fail (func != NULL);
|
||||||
|
|
||||||
|
/* Check if we need to make room */
|
||||||
|
if (G_UNLIKELY (array->length == array->size))
|
||||||
|
gst_queue_array_do_expand (array);
|
||||||
|
|
||||||
|
/* Compare against each element, assuming they're already sorted */
|
||||||
|
for (i = 0; i < array->length; i++) {
|
||||||
|
p_element = (gpointer *) gst_queue_array_idx (array, i);
|
||||||
|
|
||||||
|
if (func (*p_element, data, user_data) > 0) {
|
||||||
|
guint pos = (array->head + i) % array->size;
|
||||||
|
gst_queue_array_move_data_after_position (array, pos);
|
||||||
|
|
||||||
|
*p_element = data;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No 'bigger' element found - append to tail */
|
||||||
|
*(gpointer *) (array->array + array->elt_size * array->tail) = data;
|
||||||
|
|
||||||
|
finish:
|
||||||
|
array->tail++;
|
||||||
|
array->tail %= array->size;
|
||||||
|
array->length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_queue_array_push_sorted_struct: (skip)
|
||||||
|
* @array: a #GstQueueArray object
|
||||||
|
* @p_struct: address of element or structure to push into the queue
|
||||||
|
* @func: comparison function
|
||||||
|
* @user_data: (nullable): data for comparison function
|
||||||
|
*
|
||||||
|
* Pushes the element at address @p_struct into the queue @array
|
||||||
|
* (copying the contents of a structure of the struct_size specified
|
||||||
|
* when creating the queue into the array), finding the correct position
|
||||||
|
* by comparing the element at @p_struct with each element in the array using @func.
|
||||||
|
*
|
||||||
|
* This has a time complexity of O(n), so depending on the size of the queue
|
||||||
|
* and expected access patterns, a different data structure might be better.
|
||||||
|
*
|
||||||
|
* Assumes that the array is already sorted. If it is not, make sure
|
||||||
|
* to call gst_queue_array_sort() first.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_queue_array_push_sorted_struct (GstQueueArray * array, gpointer p_struct,
|
||||||
|
GCompareDataFunc func, gpointer user_data)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
gpointer p_element;
|
||||||
|
|
||||||
|
g_return_if_fail (array != NULL);
|
||||||
|
g_return_if_fail (p_struct != NULL);
|
||||||
|
g_return_if_fail (func != NULL);
|
||||||
|
|
||||||
|
/* Check if we need to make room */
|
||||||
|
if (G_UNLIKELY (array->length == array->size))
|
||||||
|
gst_queue_array_do_expand (array);
|
||||||
|
|
||||||
|
/* Compare against each element, assuming they're already sorted */
|
||||||
|
for (i = 0; i < array->length; i++) {
|
||||||
|
p_element = gst_queue_array_idx (array, i);
|
||||||
|
|
||||||
|
if (func (p_element, p_struct, user_data) > 0) {
|
||||||
|
guint pos = (array->head + i) % array->size;
|
||||||
|
gst_queue_array_move_data_after_position (array, pos);
|
||||||
|
|
||||||
|
memcpy (p_element, p_struct, array->elt_size);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No 'bigger' element found - append to tail */
|
||||||
|
memcpy (array->array + array->elt_size * array->tail, p_struct,
|
||||||
|
array->elt_size);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
array->tail++;
|
||||||
|
array->tail %= array->size;
|
||||||
|
array->length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_wrapper (gpointer * a, gpointer * b, QueueSortData * sort_data)
|
||||||
|
{
|
||||||
|
return sort_data->func (*a, *b, sort_data->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_queue_array_sort: (skip)
|
||||||
|
* @array: a #GstQueueArray object
|
||||||
|
* @compare_func: comparison function
|
||||||
|
* @user_data: (nullable): data for comparison function
|
||||||
|
*
|
||||||
|
* Sorts the queue @array by comparing elements against each other using
|
||||||
|
* the provided @compare_func.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_queue_array_sort (GstQueueArray * array, GCompareDataFunc compare_func,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_return_if_fail (array != NULL);
|
||||||
|
g_return_if_fail (compare_func != NULL);
|
||||||
|
|
||||||
|
if (array->length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* To be able to use g_qsort_with_data, we might need to rearrange:
|
||||||
|
* [0-----TAIL][HEAD-----SIZE] -> [HEAD-------TAIL] */
|
||||||
|
if (array->head >= array->tail) {
|
||||||
|
gsize t1 = array->head;
|
||||||
|
gsize t2 = array->size - array->head;
|
||||||
|
gsize elt_size = array->elt_size;
|
||||||
|
|
||||||
|
/* Copy [0-------TAIL] part to a temporary buffer */
|
||||||
|
guint8 *tmp = g_malloc0_n (t1, elt_size);
|
||||||
|
memcpy (tmp, array->array, t1 * elt_size);
|
||||||
|
|
||||||
|
/* Move [HEAD-----SIZE] part to the beginning of the original array */
|
||||||
|
memmove (array->array, array->array + (elt_size * array->head),
|
||||||
|
t2 * elt_size);
|
||||||
|
|
||||||
|
/* Copy the temporary buffer to the end of the original array */
|
||||||
|
memmove (array->array + (t2 * elt_size), tmp, t1 * elt_size);
|
||||||
|
g_free (tmp);
|
||||||
|
|
||||||
|
array->head = 0;
|
||||||
|
array->tail = array->length % array->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array->struct_array) {
|
||||||
|
g_qsort_with_data (array->array +
|
||||||
|
(array->head % array->size) * array->elt_size, array->length,
|
||||||
|
array->elt_size, compare_func, user_data);
|
||||||
|
} else {
|
||||||
|
/* For non-struct arrays, we need to wrap the provided compare function
|
||||||
|
* to dereference our pointers before passing them for comparison.
|
||||||
|
* This matches the behaviour of gst_queue_array_find(). */
|
||||||
|
QueueSortData sort_data = { compare_func, user_data };
|
||||||
|
g_qsort_with_data (array->array +
|
||||||
|
(array->head % array->size) * array->elt_size, array->length,
|
||||||
|
array->elt_size, (GCompareDataFunc) compare_wrapper, &sort_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_queue_array_peek_tail: (skip)
|
* gst_queue_array_peek_tail: (skip)
|
||||||
* @array: a #GstQueueArray object
|
* @array: a #GstQueueArray object
|
||||||
|
@ -718,7 +933,7 @@ gst_queue_array_drop_element (GstQueueArray * array, guint idx)
|
||||||
/**
|
/**
|
||||||
* gst_queue_array_find: (skip)
|
* gst_queue_array_find: (skip)
|
||||||
* @array: a #GstQueueArray object
|
* @array: a #GstQueueArray object
|
||||||
* @func: (allow-none): comparison function, or %NULL to find @data by value
|
* @func: (nullable): comparison function, or %NULL to find @data by value
|
||||||
* @data: data for comparison function
|
* @data: data for comparison function
|
||||||
*
|
*
|
||||||
* Finds an element in the queue @array, either by comparing every element
|
* Finds an element in the queue @array, either by comparing every element
|
||||||
|
|
|
@ -104,6 +104,23 @@ gpointer gst_queue_array_pop_tail_struct (GstQueueArray * array);
|
||||||
GST_BASE_API
|
GST_BASE_API
|
||||||
gpointer gst_queue_array_peek_tail_struct (GstQueueArray * array);
|
gpointer gst_queue_array_peek_tail_struct (GstQueueArray * array);
|
||||||
|
|
||||||
|
GST_BASE_API
|
||||||
|
void gst_queue_array_push_sorted (GstQueueArray * array,
|
||||||
|
gpointer data,
|
||||||
|
GCompareDataFunc func,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
GST_BASE_API
|
||||||
|
void gst_queue_array_push_sorted_struct (GstQueueArray * array,
|
||||||
|
gpointer p_struct,
|
||||||
|
GCompareDataFunc func,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
GST_BASE_API
|
||||||
|
void gst_queue_array_sort (GstQueueArray *array,
|
||||||
|
GCompareDataFunc compare_func,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -200,9 +200,9 @@ GST_START_TEST (test_array_grow_end)
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compare_pointer_value (gconstpointer a, gconstpointer b)
|
compare_pointer_value (guintptr a, guintptr b)
|
||||||
{
|
{
|
||||||
return (int) ((guintptr) a - (guintptr) b);
|
return (int) (a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_START_TEST (test_array_drop2)
|
GST_START_TEST (test_array_drop2)
|
||||||
|
@ -232,8 +232,8 @@ GST_START_TEST (test_array_drop2)
|
||||||
gpointer dropped;
|
gpointer dropped;
|
||||||
|
|
||||||
if (g_random_boolean () && g_random_boolean () && in_array[i]) {
|
if (g_random_boolean () && g_random_boolean () && in_array[i]) {
|
||||||
idx = gst_queue_array_find (array, compare_pointer_value,
|
idx = gst_queue_array_find (array,
|
||||||
GUINT_TO_POINTER (i));
|
(GCompareFunc) compare_pointer_value, GUINT_TO_POINTER (i));
|
||||||
dropped = gst_queue_array_drop_element (array, idx);
|
dropped = gst_queue_array_drop_element (array, idx);
|
||||||
fail_unless_equals_int (i, GPOINTER_TO_INT (dropped));
|
fail_unless_equals_int (i, GPOINTER_TO_INT (dropped));
|
||||||
in_array[i] = FALSE;
|
in_array[i] = FALSE;
|
||||||
|
@ -341,6 +341,273 @@ GST_START_TEST (test_array_peek_pop_tail)
|
||||||
|
|
||||||
GST_END_TEST;
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_array_push_sorted)
|
||||||
|
{
|
||||||
|
GstQueueArray *array;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Create an array of initial size 10 */
|
||||||
|
array = gst_queue_array_new (10);
|
||||||
|
|
||||||
|
/* Fill it with odd values */
|
||||||
|
for (i = 1; i < 10; i += 2)
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
|
||||||
|
/* Now try to push even values, in reverse order because why not */
|
||||||
|
for (i = 8; i >= 0; i -= 2)
|
||||||
|
gst_queue_array_push_sorted (array, GINT_TO_POINTER (i),
|
||||||
|
(GCompareDataFunc) compare_pointer_value, NULL);
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Check that the array is now 0-9 in correct order */
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
|
||||||
|
i);
|
||||||
|
|
||||||
|
gst_queue_array_free (array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_array_push_sorted_wrapped)
|
||||||
|
{
|
||||||
|
GstQueueArray *array;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Create an array of initial size 10 */
|
||||||
|
array = gst_queue_array_new (10);
|
||||||
|
|
||||||
|
/* Push and pull 4 values to offset head/tail.
|
||||||
|
* Pushing +1's the tail and popping +1's the head, so the push after this will
|
||||||
|
* store data at [4] internally, and further 10 pushes will cause the array
|
||||||
|
* to wrap around. */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill it with odd values */
|
||||||
|
for (i = 1; i < 10; i += 2)
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
|
||||||
|
/* Now try to push even values, in reverse order because why not */
|
||||||
|
for (i = 8; i >= 0; i -= 2)
|
||||||
|
gst_queue_array_push_sorted (array, GINT_TO_POINTER (i),
|
||||||
|
(GCompareDataFunc) compare_pointer_value, NULL);
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Check that the array is now 0-9 in correct order */
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
|
||||||
|
i);
|
||||||
|
|
||||||
|
gst_queue_array_free (array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gint value;
|
||||||
|
} CompareTestStruct;
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_struct_value (CompareTestStruct * a, CompareTestStruct * b)
|
||||||
|
{
|
||||||
|
return a->value - b->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_START_TEST (test_array_push_sorted_struct)
|
||||||
|
{
|
||||||
|
GstQueueArray *array;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Create an array of initial size 10 */
|
||||||
|
array = gst_queue_array_new_for_struct (sizeof (CompareTestStruct), 10);
|
||||||
|
|
||||||
|
/* Fill it with odd values */
|
||||||
|
for (i = 1; i < 10; i += 2) {
|
||||||
|
CompareTestStruct s = { i };
|
||||||
|
gst_queue_array_push_tail_struct (array, &s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now try to push even values, in reverse order because why not */
|
||||||
|
for (i = 8; i >= 0; i -= 2) {
|
||||||
|
CompareTestStruct s = { i };
|
||||||
|
gst_queue_array_push_sorted_struct (array, &s,
|
||||||
|
(GCompareDataFunc) compare_struct_value, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Check that the array is now 0-9 in correct order */
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
CompareTestStruct *s = gst_queue_array_pop_head_struct (array);
|
||||||
|
fail_unless_equals_int (s->value, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_queue_array_free (array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_array_push_sorted_struct_wrapped)
|
||||||
|
{
|
||||||
|
GstQueueArray *array;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Create an array of initial size 10 */
|
||||||
|
array = gst_queue_array_new_for_struct (sizeof (CompareTestStruct), 10);
|
||||||
|
|
||||||
|
/* Push and pull 4 values to offset head/tail.
|
||||||
|
* Pushing +1's the tail and popping +1's the head, so the push after this will
|
||||||
|
* store data at [4] internally, and further 10 pushes will cause the array
|
||||||
|
* to wrap around. */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill it with odd values */
|
||||||
|
for (i = 1; i < 10; i += 2) {
|
||||||
|
CompareTestStruct s = { i };
|
||||||
|
gst_queue_array_push_tail_struct (array, &s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now try to push even values, in reverse order because why not */
|
||||||
|
for (i = 8; i >= 0; i -= 2) {
|
||||||
|
CompareTestStruct s = { i };
|
||||||
|
gst_queue_array_push_sorted_struct (array, &s,
|
||||||
|
(GCompareDataFunc) compare_struct_value, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Check that the array is now 0-9 in correct order */
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
CompareTestStruct *s = gst_queue_array_pop_head_struct (array);
|
||||||
|
fail_unless_equals_int (s->value, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_queue_array_free (array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_array_sort)
|
||||||
|
{
|
||||||
|
GstQueueArray *array;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Create an array of initial size 10 */
|
||||||
|
array = gst_queue_array_new (10);
|
||||||
|
|
||||||
|
/* Fill it with odd values */
|
||||||
|
for (i = 1; i < 10; i += 2)
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
|
||||||
|
/* Now try to push even values, in reverse order because why not */
|
||||||
|
for (i = 8; i >= 0; i -= 2)
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Sort the array */
|
||||||
|
gst_queue_array_sort (array, (GCompareDataFunc) compare_pointer_value, NULL);
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Check that the array is now 0-9 in correct order */
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
|
||||||
|
i);
|
||||||
|
|
||||||
|
gst_queue_array_free (array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_array_sort_struct)
|
||||||
|
{
|
||||||
|
GstQueueArray *array;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Create an array of initial size 10 */
|
||||||
|
array = gst_queue_array_new_for_struct (sizeof (CompareTestStruct), 10);
|
||||||
|
|
||||||
|
/* Fill it with odd values */
|
||||||
|
for (i = 1; i < 10; i += 2) {
|
||||||
|
CompareTestStruct s = { i };
|
||||||
|
gst_queue_array_push_tail_struct (array, &s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now try to push even values, in reverse order because why not */
|
||||||
|
for (i = 8; i >= 0; i -= 2) {
|
||||||
|
CompareTestStruct s = { i };
|
||||||
|
gst_queue_array_push_tail_struct (array, &s);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Sort the array */
|
||||||
|
gst_queue_array_sort (array, (GCompareDataFunc) compare_struct_value, NULL);
|
||||||
|
|
||||||
|
/* Check that the array is now 0-9 in correct order */
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
CompareTestStruct *s = gst_queue_array_pop_head_struct (array);
|
||||||
|
fail_unless_equals_int (s->value, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_queue_array_free (array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
|
GST_START_TEST (test_array_sort_wrapped)
|
||||||
|
{
|
||||||
|
GstQueueArray *array;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* Create an array of initial size 10 */
|
||||||
|
array = gst_queue_array_new (10);
|
||||||
|
|
||||||
|
/* Push and pull 4 values to offset head/tail */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
|
||||||
|
i);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 0);
|
||||||
|
|
||||||
|
/* Fill it with odd values */
|
||||||
|
for (i = 1; i < 10; i += 2)
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
|
||||||
|
/* Now try to push even values, in reverse order because why not
|
||||||
|
* At this point the array should've wrapped around (head > tail) */
|
||||||
|
for (i = 8; i >= 0; i -= 2)
|
||||||
|
gst_queue_array_push_tail (array, GINT_TO_POINTER (i));
|
||||||
|
|
||||||
|
fail_unless_equals_int (gst_queue_array_get_length (array), 10);
|
||||||
|
|
||||||
|
/* Sort the array */
|
||||||
|
gst_queue_array_sort (array, (GCompareDataFunc) compare_pointer_value, NULL);
|
||||||
|
|
||||||
|
/* Check that the array is now 0-9 in correct order */
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
fail_unless_equals_int (GPOINTER_TO_INT (gst_queue_array_pop_head (array)),
|
||||||
|
i);
|
||||||
|
|
||||||
|
gst_queue_array_free (array);
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_END_TEST;
|
||||||
|
|
||||||
static Suite *
|
static Suite *
|
||||||
gst_queue_array_suite (void)
|
gst_queue_array_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -358,6 +625,13 @@ gst_queue_array_suite (void)
|
||||||
tcase_add_test (tc_chain, test_array_grow_from_prealloc1);
|
tcase_add_test (tc_chain, test_array_grow_from_prealloc1);
|
||||||
tcase_add_test (tc_chain, test_array_peek_pop_tail);
|
tcase_add_test (tc_chain, test_array_peek_pop_tail);
|
||||||
tcase_add_test (tc_chain, test_array_peek_nth);
|
tcase_add_test (tc_chain, test_array_peek_nth);
|
||||||
|
tcase_add_test (tc_chain, test_array_push_sorted);
|
||||||
|
tcase_add_test (tc_chain, test_array_push_sorted_wrapped);
|
||||||
|
tcase_add_test (tc_chain, test_array_push_sorted_struct);
|
||||||
|
tcase_add_test (tc_chain, test_array_push_sorted_struct_wrapped);
|
||||||
|
tcase_add_test (tc_chain, test_array_sort);
|
||||||
|
tcase_add_test (tc_chain, test_array_sort_struct);
|
||||||
|
tcase_add_test (tc_chain, test_array_sort_wrapped);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue