2009-09-28 15:30:04 +00:00
|
|
|
/* GStreamer
|
|
|
|
* Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
|
2015-05-30 12:07:50 +00:00
|
|
|
* Copyright (C) 2015 Tim-Philipp Müller <tim@centricular.com>
|
2009-09-28 15:30:04 +00:00
|
|
|
*
|
|
|
|
* gstqueuearray.c:
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
2012-11-03 20:44:48 +00:00
|
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
2009-09-28 15:30:04 +00:00
|
|
|
*/
|
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
/**
|
|
|
|
* SECTION:gstqueuearray
|
2017-01-16 14:26:16 +00:00
|
|
|
* @title: GstQueueArray
|
2012-10-22 08:13:20 +00:00
|
|
|
* @short_description: Array based queue object
|
|
|
|
*
|
|
|
|
* #GstQueueArray is an object that provides standard queue functionality
|
|
|
|
* based on an array instead of linked lists. This reduces the overhead
|
2013-12-07 14:38:19 +00:00
|
|
|
* caused by memory management by a large factor.
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
2018-08-25 21:56:01 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
2012-10-22 08:13:20 +00:00
|
|
|
|
2009-09-28 15:30:04 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <gst/gst.h>
|
|
|
|
#include "gstqueuearray.h"
|
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
struct _GstQueueArray
|
2009-09-28 15:30:04 +00:00
|
|
|
{
|
2012-10-22 08:13:20 +00:00
|
|
|
/* < private > */
|
2015-05-30 12:07:50 +00:00
|
|
|
guint8 *array;
|
2012-10-22 08:13:20 +00:00
|
|
|
guint size;
|
|
|
|
guint head;
|
|
|
|
guint tail;
|
|
|
|
guint length;
|
2015-05-30 12:07:50 +00:00
|
|
|
guint elt_size;
|
|
|
|
gboolean struct_array;
|
2018-09-27 14:30:25 +00:00
|
|
|
GDestroyNotify clear_func;
|
2012-10-22 08:13:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2015-05-30 12:07:50 +00:00
|
|
|
* gst_queue_array_new_for_struct: (skip)
|
|
|
|
* @struct_size: Size of each element (e.g. structure) in the array
|
2012-10-22 08:13:20 +00:00
|
|
|
* @initial_size: Initial size of the new queue
|
|
|
|
*
|
2015-05-30 12:07:50 +00:00
|
|
|
* Allocates a new #GstQueueArray object for elements (e.g. structures)
|
|
|
|
* of size @struct_size, with an initial queue size of @initial_size.
|
2012-10-22 08:13:20 +00:00
|
|
|
*
|
|
|
|
* Returns: a new #GstQueueArray object
|
|
|
|
*
|
2015-05-30 12:07:50 +00:00
|
|
|
* Since: 1.6
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
|
|
|
GstQueueArray *
|
2015-05-30 12:07:50 +00:00
|
|
|
gst_queue_array_new_for_struct (gsize struct_size, guint initial_size)
|
2012-10-22 08:13:20 +00:00
|
|
|
{
|
|
|
|
GstQueueArray *array;
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
g_return_val_if_fail (struct_size > 0, NULL);
|
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
array = g_slice_new (GstQueueArray);
|
2015-05-30 12:07:50 +00:00
|
|
|
array->elt_size = struct_size;
|
2009-09-28 15:30:04 +00:00
|
|
|
array->size = initial_size;
|
2015-05-30 12:07:50 +00:00
|
|
|
array->array = g_malloc0 (struct_size * initial_size);
|
2009-09-28 15:30:04 +00:00
|
|
|
array->head = 0;
|
|
|
|
array->tail = 0;
|
|
|
|
array->length = 0;
|
2015-05-30 12:07:50 +00:00
|
|
|
array->struct_array = TRUE;
|
2018-09-27 14:30:25 +00:00
|
|
|
array->clear_func = NULL;
|
2012-10-22 08:13:20 +00:00
|
|
|
return array;
|
2012-07-14 18:38:39 +00:00
|
|
|
}
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_new: (skip)
|
|
|
|
* @initial_size: Initial size of the new queue
|
|
|
|
*
|
|
|
|
* Allocates a new #GstQueueArray object with an initial
|
|
|
|
* queue size of @initial_size.
|
|
|
|
*
|
|
|
|
* Returns: a new #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Since: 1.2
|
|
|
|
*/
|
|
|
|
GstQueueArray *
|
|
|
|
gst_queue_array_new (guint initial_size)
|
|
|
|
{
|
|
|
|
GstQueueArray *array;
|
|
|
|
|
|
|
|
array = gst_queue_array_new_for_struct (sizeof (gpointer), initial_size);
|
|
|
|
array->struct_array = FALSE;
|
|
|
|
return array;
|
|
|
|
}
|
2012-07-14 18:38:39 +00:00
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
/**
|
2014-06-26 17:30:52 +00:00
|
|
|
* gst_queue_array_free: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Frees queue @array and all memory associated to it.
|
|
|
|
*
|
2013-11-16 12:24:56 +00:00
|
|
|
* Since: 1.2
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_queue_array_free (GstQueueArray * array)
|
|
|
|
{
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_if_fail (array != NULL);
|
2018-09-27 14:30:25 +00:00
|
|
|
gst_queue_array_clear (array);
|
2012-10-22 08:13:20 +00:00
|
|
|
g_free (array->array);
|
|
|
|
g_slice_free (GstQueueArray, array);
|
2009-09-28 15:30:04 +00:00
|
|
|
}
|
|
|
|
|
2018-09-27 14:30:25 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_set_clear_func: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
* @clear_func: a function to clear an element of @array
|
|
|
|
*
|
|
|
|
* Sets a function to clear an element of @array.
|
|
|
|
*
|
|
|
|
* The @clear_func will be called when an element in the array
|
|
|
|
* data segment is removed and when the array is freed and data
|
|
|
|
* segment is deallocated as well. @clear_func will be passed a
|
|
|
|
* pointer to the element to clear, rather than the element itself.
|
|
|
|
*
|
|
|
|
* Note that in contrast with other uses of #GDestroyNotify
|
|
|
|
* functions, @clear_func is expected to clear the contents of
|
|
|
|
* the array element it is given, but not free the element itself.
|
|
|
|
*
|
|
|
|
* Since: 1.16
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_queue_array_set_clear_func (GstQueueArray * array,
|
|
|
|
GDestroyNotify clear_func)
|
|
|
|
{
|
|
|
|
g_return_if_fail (array != NULL);
|
|
|
|
array->clear_func = clear_func;
|
|
|
|
}
|
|
|
|
|
2018-10-15 12:24:07 +00:00
|
|
|
static void
|
|
|
|
gst_queue_array_clear_idx (GstQueueArray * array, guint idx)
|
|
|
|
{
|
|
|
|
guint pos;
|
|
|
|
|
|
|
|
if (!array->clear_func)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pos = (idx + array->head) % array->size;
|
|
|
|
if (array->struct_array)
|
|
|
|
array->clear_func (array->array + pos * array->elt_size);
|
|
|
|
else
|
|
|
|
array->clear_func (*(gpointer *) (array->array + pos * array->elt_size));
|
|
|
|
}
|
|
|
|
|
2018-09-27 14:30:25 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_clear: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Clears queue @array and frees all memory associated to it.
|
|
|
|
*
|
|
|
|
* Since: 1.16
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_queue_array_clear (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
g_return_if_fail (array != NULL);
|
|
|
|
|
|
|
|
if (array->clear_func != NULL) {
|
2018-10-15 12:24:07 +00:00
|
|
|
guint i;
|
2018-09-27 14:30:25 +00:00
|
|
|
|
|
|
|
for (i = 0; i < array->length; i++) {
|
2018-10-15 12:24:07 +00:00
|
|
|
gst_queue_array_clear_idx (array, i);
|
2018-09-27 14:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
array->head = 0;
|
|
|
|
array->tail = 0;
|
|
|
|
array->length = 0;
|
|
|
|
}
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_pop_head_struct: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns the head of the queue @array and removes it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: pointer to element or struct, or NULL if @array was empty. The
|
|
|
|
* data pointed to by the returned pointer stays valid only as long as
|
|
|
|
* the queue array is not modified further!
|
|
|
|
*
|
|
|
|
* Since: 1.6
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_pop_head_struct (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
gpointer p_struct;
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
2015-05-30 12:07:50 +00:00
|
|
|
/* empty array */
|
|
|
|
if (G_UNLIKELY (array->length == 0))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
p_struct = array->array + (array->elt_size * array->head);
|
|
|
|
|
|
|
|
array->head++;
|
|
|
|
array->head %= array->size;
|
|
|
|
array->length--;
|
|
|
|
|
|
|
|
return p_struct;
|
|
|
|
}
|
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
/**
|
2014-06-26 17:30:52 +00:00
|
|
|
* gst_queue_array_pop_head: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns and head of the queue @array and removes
|
|
|
|
* it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The head of the queue
|
|
|
|
*
|
2013-11-16 12:24:56 +00:00
|
|
|
* Since: 1.2
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
2009-09-28 15:30:04 +00:00
|
|
|
gpointer
|
|
|
|
gst_queue_array_pop_head (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
gpointer ret;
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
2018-02-01 18:29:27 +00:00
|
|
|
|
2009-09-28 15:30:04 +00:00
|
|
|
/* empty array */
|
|
|
|
if (G_UNLIKELY (array->length == 0))
|
|
|
|
return NULL;
|
2015-05-30 12:07:50 +00:00
|
|
|
|
|
|
|
ret = *(gpointer *) (array->array + (sizeof (gpointer) * array->head));
|
2009-09-28 15:30:04 +00:00
|
|
|
array->head++;
|
|
|
|
array->head %= array->size;
|
|
|
|
array->length--;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_peek_head_struct: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns the head of the queue @array without removing it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: pointer to element or struct, or NULL if @array was empty. The
|
|
|
|
* data pointed to by the returned pointer stays valid only as long as
|
|
|
|
* the queue array is not modified further!
|
|
|
|
*
|
|
|
|
* Since: 1.6
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_peek_head_struct (GstQueueArray * array)
|
|
|
|
{
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
2015-05-30 12:07:50 +00:00
|
|
|
/* empty array */
|
|
|
|
if (G_UNLIKELY (array->length == 0))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return array->array + (array->elt_size * array->head);
|
|
|
|
}
|
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
/**
|
2014-06-26 17:30:52 +00:00
|
|
|
* gst_queue_array_peek_head: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
2015-05-30 12:07:50 +00:00
|
|
|
* Returns the head of the queue @array and does not
|
2012-10-22 08:13:20 +00:00
|
|
|
* remove it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The head of the queue
|
|
|
|
*
|
2013-11-16 12:24:56 +00:00
|
|
|
* Since: 1.2
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_peek_head (GstQueueArray * array)
|
|
|
|
{
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
2012-10-22 08:13:20 +00:00
|
|
|
/* empty array */
|
|
|
|
if (G_UNLIKELY (array->length == 0))
|
|
|
|
return NULL;
|
2015-05-30 12:07:50 +00:00
|
|
|
|
|
|
|
return *(gpointer *) (array->array + (sizeof (gpointer) * array->head));
|
|
|
|
}
|
|
|
|
|
2018-04-11 13:38:36 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_peek_nth: (skip)
|
|
|
|
*
|
|
|
|
* Returns the item at @idx in @array, but does not remove it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The item, or %NULL if @idx was out of bounds
|
|
|
|
*
|
|
|
|
* Since: 1.16
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_peek_nth (GstQueueArray * array, guint idx)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
|
|
|
g_return_val_if_fail (idx < array->length, NULL);
|
|
|
|
|
|
|
|
idx = (array->head + idx) % array->size;
|
|
|
|
|
|
|
|
return *(gpointer *) (array->array + (sizeof (gpointer) * idx));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_queue_array_peek_nth_struct: (skip)
|
|
|
|
*
|
|
|
|
* Returns the item at @idx in @array, but does not remove it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The item, or %NULL if @idx was out of bounds
|
|
|
|
*
|
|
|
|
* Since: 1.16
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_peek_nth_struct (GstQueueArray * array, guint idx)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
|
|
|
g_return_val_if_fail (idx < array->length, NULL);
|
|
|
|
|
|
|
|
idx = (array->head + idx) % array->size;
|
|
|
|
|
|
|
|
return array->array + (array->elt_size * idx);
|
|
|
|
}
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
static void
|
|
|
|
gst_queue_array_do_expand (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
guint elt_size = array->elt_size;
|
|
|
|
/* newsize is 50% bigger */
|
|
|
|
guint oldsize = array->size;
|
|
|
|
guint newsize = MAX ((3 * oldsize) / 2, oldsize + 1);
|
|
|
|
|
|
|
|
/* copy over data */
|
|
|
|
if (array->tail != 0) {
|
|
|
|
guint8 *array2 = g_malloc0 (elt_size * newsize);
|
|
|
|
guint t1 = array->head;
|
|
|
|
guint t2 = oldsize - array->head;
|
|
|
|
|
|
|
|
/* [0-----TAIL][HEAD------SIZE]
|
|
|
|
*
|
|
|
|
* We want to end up with
|
|
|
|
* [HEAD------------------TAIL][----FREEDATA------NEWSIZE]
|
|
|
|
*
|
|
|
|
* 1) move [HEAD-----SIZE] part to beginning of new array
|
|
|
|
* 2) move [0-------TAIL] part new array, after previous part
|
|
|
|
*/
|
|
|
|
|
|
|
|
memcpy (array2, array->array + (elt_size * array->head), t2 * elt_size);
|
|
|
|
memcpy (array2 + t2 * elt_size, array->array, t1 * elt_size);
|
|
|
|
|
|
|
|
g_free (array->array);
|
|
|
|
array->array = array2;
|
|
|
|
array->head = 0;
|
|
|
|
} else {
|
|
|
|
/* Fast path, we just need to grow the array */
|
|
|
|
array->array = g_realloc (array->array, elt_size * newsize);
|
|
|
|
memset (array->array + elt_size * oldsize, 0,
|
|
|
|
elt_size * (newsize - oldsize));
|
|
|
|
}
|
|
|
|
array->tail = oldsize;
|
|
|
|
array->size = newsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_queue_array_push_element_tail: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
* @p_struct: address of element or structure to push to the tail of the queue
|
|
|
|
*
|
|
|
|
* Pushes the element at address @p_struct to the tail of the queue @array
|
|
|
|
* (Copies the contents of a structure of the struct_size specified when
|
|
|
|
* creating the queue into the array).
|
|
|
|
*
|
|
|
|
* Since: 1.6
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_queue_array_push_tail_struct (GstQueueArray * array, gpointer p_struct)
|
|
|
|
{
|
|
|
|
guint elt_size;
|
|
|
|
|
|
|
|
g_return_if_fail (p_struct != NULL);
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_if_fail (array != NULL);
|
2015-05-30 12:07:50 +00:00
|
|
|
elt_size = array->elt_size;
|
|
|
|
|
|
|
|
/* Check if we need to make room */
|
|
|
|
if (G_UNLIKELY (array->length == array->size))
|
|
|
|
gst_queue_array_do_expand (array);
|
|
|
|
|
|
|
|
memcpy (array->array + elt_size * array->tail, p_struct, elt_size);
|
|
|
|
array->tail++;
|
|
|
|
array->tail %= array->size;
|
|
|
|
array->length++;
|
2012-10-22 08:13:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2014-06-26 17:30:52 +00:00
|
|
|
* gst_queue_array_push_tail: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
* @data: object to push
|
|
|
|
*
|
|
|
|
* Pushes @data to the tail of the queue @array.
|
|
|
|
*
|
2013-11-16 12:24:56 +00:00
|
|
|
* Since: 1.2
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
2009-09-28 15:30:04 +00:00
|
|
|
void
|
|
|
|
gst_queue_array_push_tail (GstQueueArray * array, gpointer data)
|
|
|
|
{
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_if_fail (array != NULL);
|
2018-02-01 18:29:27 +00:00
|
|
|
|
2009-09-28 15:30:04 +00:00
|
|
|
/* Check if we need to make room */
|
2015-05-30 12:07:50 +00:00
|
|
|
if (G_UNLIKELY (array->length == array->size))
|
|
|
|
gst_queue_array_do_expand (array);
|
2009-09-28 15:30:04 +00:00
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
*(gpointer *) (array->array + sizeof (gpointer) * array->tail) = data;
|
2009-09-28 15:30:04 +00:00
|
|
|
array->tail++;
|
|
|
|
array->tail %= array->size;
|
|
|
|
array->length++;
|
|
|
|
}
|
|
|
|
|
2018-02-01 18:29:27 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_peek_tail: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns the tail of the queue @array, but does not remove it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The tail of the queue
|
|
|
|
*
|
|
|
|
* Since: 1.14
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_peek_tail (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
guint len, idx;
|
|
|
|
|
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
|
|
|
|
|
|
|
len = array->length;
|
|
|
|
|
|
|
|
/* empty array */
|
|
|
|
if (len == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
idx = (array->head + (len - 1)) % array->size;
|
|
|
|
|
|
|
|
return *(gpointer *) (array->array + (sizeof (gpointer) * idx));
|
|
|
|
}
|
|
|
|
|
2018-03-01 21:19:09 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_peek_tail_struct: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns the tail of the queue @array, but does not remove it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The tail of the queue
|
|
|
|
*
|
|
|
|
* Since: 1.14
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_peek_tail_struct (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
guint len, idx;
|
|
|
|
|
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
|
|
|
|
|
|
|
len = array->length;
|
|
|
|
|
|
|
|
/* empty array */
|
|
|
|
if (len == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
idx = (array->head + (len - 1)) % array->size;
|
|
|
|
|
|
|
|
return array->array + (array->elt_size * idx);
|
|
|
|
}
|
|
|
|
|
2018-02-01 18:29:27 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_pop_tail: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns the tail of the queue @array and removes
|
|
|
|
* it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The tail of the queue
|
|
|
|
*
|
|
|
|
* Since: 1.14
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_pop_tail (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
gpointer ret;
|
|
|
|
guint len, idx;
|
|
|
|
|
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
|
|
|
|
|
|
|
len = array->length;
|
|
|
|
|
|
|
|
/* empty array */
|
|
|
|
if (len == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
idx = (array->head + (len - 1)) % array->size;
|
|
|
|
|
|
|
|
ret = *(gpointer *) (array->array + (sizeof (gpointer) * idx));
|
|
|
|
|
|
|
|
array->tail = idx;
|
|
|
|
array->length--;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-03-04 08:53:10 +00:00
|
|
|
/**
|
|
|
|
* gst_queue_array_pop_tail_struct: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns the tail of the queue @array and removes
|
|
|
|
* it from the queue.
|
|
|
|
*
|
|
|
|
* Returns: The tail of the queue
|
|
|
|
*
|
|
|
|
* Since: 1.14
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_pop_tail_struct (GstQueueArray * array)
|
|
|
|
{
|
|
|
|
gpointer ret;
|
|
|
|
guint len, idx;
|
|
|
|
|
|
|
|
g_return_val_if_fail (array != NULL, NULL);
|
|
|
|
|
|
|
|
len = array->length;
|
|
|
|
|
|
|
|
/* empty array */
|
|
|
|
if (len == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
idx = (array->head + (len - 1)) % array->size;
|
|
|
|
|
|
|
|
ret = array->array + (array->elt_size * idx);
|
|
|
|
|
|
|
|
array->tail = idx;
|
|
|
|
array->length--;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
/**
|
2014-06-26 17:30:52 +00:00
|
|
|
* gst_queue_array_is_empty: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Checks if the queue @array is empty.
|
|
|
|
*
|
|
|
|
* Returns: %TRUE if the queue @array is empty
|
|
|
|
*
|
2013-11-16 12:24:56 +00:00
|
|
|
* Since: 1.2
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
2009-09-28 15:30:04 +00:00
|
|
|
gboolean
|
|
|
|
gst_queue_array_is_empty (GstQueueArray * array)
|
|
|
|
{
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_val_if_fail (array != NULL, FALSE);
|
2009-09-28 15:30:04 +00:00
|
|
|
return (array->length == 0);
|
|
|
|
}
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
/**
|
2015-05-30 12:07:50 +00:00
|
|
|
* gst_queue_array_drop_struct: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
* @idx: index to drop
|
2015-05-30 12:07:50 +00:00
|
|
|
* @p_struct: address into which to store the data of the dropped structure, or NULL
|
2012-10-22 08:13:20 +00:00
|
|
|
*
|
2015-05-30 12:07:50 +00:00
|
|
|
* Drops the queue element at position @idx from queue @array and copies the
|
|
|
|
* data of the element or structure that was removed into @p_struct if
|
|
|
|
* @p_struct is set (not NULL).
|
2012-10-22 08:13:20 +00:00
|
|
|
*
|
2015-05-30 12:07:50 +00:00
|
|
|
* Returns: TRUE on success, or FALSE on error
|
2012-10-22 08:13:20 +00:00
|
|
|
*
|
2015-05-30 12:07:50 +00:00
|
|
|
* Since: 1.6
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
2015-05-30 12:07:50 +00:00
|
|
|
gboolean
|
|
|
|
gst_queue_array_drop_struct (GstQueueArray * array, guint idx,
|
|
|
|
gpointer p_struct)
|
2009-09-28 15:30:04 +00:00
|
|
|
{
|
2013-01-28 10:05:28 +00:00
|
|
|
int first_item_index, last_item_index;
|
2018-10-15 12:24:07 +00:00
|
|
|
guint actual_idx;
|
2015-05-30 12:07:50 +00:00
|
|
|
guint elt_size;
|
|
|
|
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_val_if_fail (array != NULL, FALSE);
|
2018-10-15 12:24:07 +00:00
|
|
|
actual_idx = (array->head + idx) % array->size;
|
2018-04-11 11:44:33 +00:00
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
g_return_val_if_fail (array->length > 0, FALSE);
|
2018-10-15 12:24:07 +00:00
|
|
|
g_return_val_if_fail (actual_idx < array->size, FALSE);
|
2012-10-22 08:13:20 +00:00
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
elt_size = array->elt_size;
|
2013-01-28 10:05:28 +00:00
|
|
|
|
|
|
|
first_item_index = array->head;
|
|
|
|
|
|
|
|
/* tail points to the first free spot */
|
|
|
|
last_item_index = (array->tail - 1 + array->size) % array->size;
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
if (p_struct != NULL)
|
2018-10-15 12:24:07 +00:00
|
|
|
memcpy (p_struct, array->array + elt_size * actual_idx, elt_size);
|
|
|
|
|
|
|
|
/* simple case actual_idx == first item */
|
|
|
|
if (actual_idx == first_item_index) {
|
|
|
|
/* clear current head position if needed */
|
2018-10-15 15:47:16 +00:00
|
|
|
if (p_struct == NULL)
|
|
|
|
gst_queue_array_clear_idx (array, idx);
|
2013-01-28 10:05:28 +00:00
|
|
|
|
|
|
|
/* move the head plus one */
|
2009-09-28 15:30:04 +00:00
|
|
|
array->head++;
|
|
|
|
array->head %= array->size;
|
2013-01-28 10:05:28 +00:00
|
|
|
array->length--;
|
2015-05-30 12:07:50 +00:00
|
|
|
return TRUE;
|
2009-09-28 15:30:04 +00:00
|
|
|
}
|
2013-01-28 10:05:28 +00:00
|
|
|
|
|
|
|
/* simple case idx == last item */
|
2018-10-15 12:24:07 +00:00
|
|
|
if (actual_idx == last_item_index) {
|
|
|
|
/* clear current tail position if needed */
|
2018-10-15 15:47:16 +00:00
|
|
|
if (p_struct == NULL)
|
|
|
|
gst_queue_array_clear_idx (array, idx);
|
2018-10-15 12:24:07 +00:00
|
|
|
|
2013-01-28 10:05:28 +00:00
|
|
|
/* move tail minus one, potentially wrapping */
|
2009-09-28 15:30:04 +00:00
|
|
|
array->tail = (array->tail - 1 + array->size) % array->size;
|
2013-01-28 10:05:28 +00:00
|
|
|
array->length--;
|
2015-05-30 12:07:50 +00:00
|
|
|
return TRUE;
|
2009-09-28 15:30:04 +00:00
|
|
|
}
|
2013-01-28 10:05:28 +00:00
|
|
|
|
|
|
|
/* non-wrapped case */
|
|
|
|
if (first_item_index < last_item_index) {
|
2018-10-15 12:24:07 +00:00
|
|
|
/* clear idx if needed */
|
2018-10-15 15:47:16 +00:00
|
|
|
if (p_struct == NULL)
|
|
|
|
gst_queue_array_clear_idx (array, idx);
|
2018-10-15 12:24:07 +00:00
|
|
|
|
|
|
|
g_assert (first_item_index < actual_idx && actual_idx < last_item_index);
|
|
|
|
/* move everything beyond actual_idx one step towards zero in array */
|
|
|
|
memmove (array->array + elt_size * actual_idx,
|
|
|
|
array->array + elt_size * (actual_idx + 1),
|
|
|
|
(last_item_index - actual_idx) * elt_size);
|
2013-01-28 10:05:28 +00:00
|
|
|
/* tail might wrap, ie if tail == 0 (and last_item_index == size) */
|
|
|
|
array->tail = (array->tail - 1 + array->size) % array->size;
|
|
|
|
array->length--;
|
2015-05-30 12:07:50 +00:00
|
|
|
return TRUE;
|
2013-01-28 10:05:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* only wrapped cases left */
|
|
|
|
g_assert (first_item_index > last_item_index);
|
|
|
|
|
2018-10-15 12:24:07 +00:00
|
|
|
if (actual_idx < last_item_index) {
|
|
|
|
/* clear idx if needed */
|
2018-10-15 15:47:16 +00:00
|
|
|
if (p_struct == NULL)
|
|
|
|
gst_queue_array_clear_idx (array, idx);
|
2018-10-15 12:24:07 +00:00
|
|
|
|
|
|
|
/* actual_idx is before last_item_index, move data towards zero */
|
|
|
|
memmove (array->array + elt_size * actual_idx,
|
|
|
|
array->array + elt_size * (actual_idx + 1),
|
|
|
|
(last_item_index - actual_idx) * elt_size);
|
2013-01-28 10:05:28 +00:00
|
|
|
/* tail should not wrap in this case! */
|
|
|
|
g_assert (array->tail > 0);
|
2009-09-28 15:30:04 +00:00
|
|
|
array->tail--;
|
2013-01-28 10:05:28 +00:00
|
|
|
array->length--;
|
2015-05-30 12:07:50 +00:00
|
|
|
return TRUE;
|
2009-09-28 15:30:04 +00:00
|
|
|
}
|
2013-01-28 10:05:28 +00:00
|
|
|
|
2018-10-15 12:24:07 +00:00
|
|
|
if (actual_idx > first_item_index) {
|
|
|
|
/* clear idx if needed */
|
2018-10-15 15:47:16 +00:00
|
|
|
if (p_struct == NULL)
|
|
|
|
gst_queue_array_clear_idx (array, idx);
|
2018-10-15 12:24:07 +00:00
|
|
|
|
|
|
|
/* actual_idx is after first_item_index, move data to higher indices */
|
2015-05-30 12:07:50 +00:00
|
|
|
memmove (array->array + elt_size * (first_item_index + 1),
|
|
|
|
array->array + elt_size * first_item_index,
|
2018-10-15 12:24:07 +00:00
|
|
|
(actual_idx - first_item_index) * elt_size);
|
2013-01-28 10:05:28 +00:00
|
|
|
array->head++;
|
|
|
|
/* head should not wrap in this case! */
|
|
|
|
g_assert (array->head < array->size);
|
|
|
|
array->length--;
|
2015-05-30 12:07:50 +00:00
|
|
|
return TRUE;
|
2013-01-28 10:05:28 +00:00
|
|
|
}
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
g_return_val_if_reached (FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_queue_array_drop_element: (skip)
|
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
* @idx: index to drop
|
|
|
|
*
|
|
|
|
* Drops the queue element at position @idx from queue @array.
|
|
|
|
*
|
|
|
|
* Returns: the dropped element
|
|
|
|
*
|
|
|
|
* Since: 1.2
|
|
|
|
*/
|
|
|
|
gpointer
|
|
|
|
gst_queue_array_drop_element (GstQueueArray * array, guint idx)
|
|
|
|
{
|
|
|
|
gpointer ptr;
|
|
|
|
|
|
|
|
if (!gst_queue_array_drop_struct (array, idx, &ptr))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return ptr;
|
2009-09-28 15:30:04 +00:00
|
|
|
}
|
|
|
|
|
2012-10-22 08:13:20 +00:00
|
|
|
/**
|
2014-06-26 17:30:52 +00:00
|
|
|
* gst_queue_array_find: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
2013-01-30 11:55:18 +00:00
|
|
|
* @func: (allow-none): comparison function, or %NULL to find @data by value
|
2012-10-22 08:13:20 +00:00
|
|
|
* @data: data for comparison function
|
|
|
|
*
|
2013-01-30 11:55:18 +00:00
|
|
|
* Finds an element in the queue @array, either by comparing every element
|
|
|
|
* with @func or by looking up @data if no compare function @func is provided,
|
|
|
|
* and returning the index of the found element.
|
|
|
|
*
|
2012-10-22 08:13:20 +00:00
|
|
|
* Returns: Index of the found element or -1 if nothing was found.
|
|
|
|
*
|
2013-11-16 12:24:56 +00:00
|
|
|
* Since: 1.2
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
2009-09-28 15:30:04 +00:00
|
|
|
guint
|
|
|
|
gst_queue_array_find (GstQueueArray * array, GCompareFunc func, gpointer data)
|
|
|
|
{
|
2015-05-30 12:07:50 +00:00
|
|
|
gpointer p_element;
|
|
|
|
guint elt_size;
|
2009-09-28 15:30:04 +00:00
|
|
|
guint i;
|
|
|
|
|
2015-05-30 12:07:50 +00:00
|
|
|
/* For struct arrays we need to implement this differently so that
|
|
|
|
* the user gets a pointer to the element data not the dereferenced
|
|
|
|
* pointer itself */
|
2017-10-16 10:36:37 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (array != NULL, -1);
|
2015-05-30 12:07:50 +00:00
|
|
|
g_return_val_if_fail (array->struct_array == FALSE, -1);
|
|
|
|
|
|
|
|
elt_size = array->elt_size;
|
|
|
|
|
2013-01-30 11:55:18 +00:00
|
|
|
if (func != NULL) {
|
|
|
|
/* Scan from head to tail */
|
|
|
|
for (i = 0; i < array->length; i++) {
|
2015-05-30 12:07:50 +00:00
|
|
|
p_element = array->array + ((i + array->head) % array->size) * elt_size;
|
|
|
|
if (func (*(gpointer *) p_element, data) == 0)
|
2018-04-11 11:44:33 +00:00
|
|
|
return i;
|
2013-01-30 11:55:18 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < array->length; i++) {
|
2015-05-30 12:07:50 +00:00
|
|
|
p_element = array->array + ((i + array->head) % array->size) * elt_size;
|
|
|
|
if (*(gpointer *) p_element == data)
|
2018-04-11 11:44:33 +00:00
|
|
|
return i;
|
2013-01-30 11:55:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-28 15:30:04 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-10-22 08:13:20 +00:00
|
|
|
|
|
|
|
/**
|
2014-06-26 17:30:52 +00:00
|
|
|
* gst_queue_array_get_length: (skip)
|
2012-10-22 08:13:20 +00:00
|
|
|
* @array: a #GstQueueArray object
|
|
|
|
*
|
|
|
|
* Returns the length of the queue @array
|
|
|
|
*
|
|
|
|
* Returns: the length of the queue @array.
|
|
|
|
*
|
2013-11-16 12:24:56 +00:00
|
|
|
* Since: 1.2
|
2012-10-22 08:13:20 +00:00
|
|
|
*/
|
|
|
|
guint
|
|
|
|
gst_queue_array_get_length (GstQueueArray * array)
|
|
|
|
{
|
2017-10-16 10:36:37 +00:00
|
|
|
g_return_val_if_fail (array != NULL, 0);
|
2012-10-22 08:13:20 +00:00
|
|
|
return array->length;
|
|
|
|
}
|