2 * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
4 * gstiterator.h: Base class for iterating datastructures.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
24 * @short_description: Object to retrieve multiple elements in a threadsafe
26 * @see_also: #GstElement, #GstBin
28 * A GstIterator is used to retrieve multiple objects from another object in
31 * Various GStreamer objects provide access to their internal structures using
34 * In general, whenever calling a GstIterator function results in your code
35 * receiving a refcounted object, the refcount for that object will have been
36 * increased. Your code is responsible for unrefing that object after use.
38 * The basic use pattern of an iterator is as follows:
41 * <title>Using an iterator</title>
43 * it = _get_iterator(object);
46 * switch (gst_iterator_next (it, &item)) {
47 * case GST_ITERATOR_OK:
48 * ... use/change item here...
49 * gst_object_unref (item);
51 * case GST_ITERATOR_RESYNC:
52 * ...rollback changes to items...
53 * gst_iterator_resync (it);
55 * case GST_ITERATOR_ERROR:
56 * ...wrong parameters were given...
59 * case GST_ITERATOR_DONE:
64 * gst_iterator_free (it);
68 * Last reviewed on 2009-06-16 (0.10.24)
71 #include "gst_private.h"
72 #include <gst/gstiterator.h>
75 gst_iterator_init (GstIterator * it,
78 guint32 * master_cookie,
79 GstIteratorNextFunction next,
80 GstIteratorItemFunction item,
81 GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
85 it->master_cookie = master_cookie;
86 it->cookie = *master_cookie;
96 * @size: the size of the iterator structure
97 * @type: #GType of children
98 * @lock: pointer to a #GMutex.
99 * @master_cookie: pointer to a guint32 that is changed when the items in the
101 * @next: function to get next item
102 * @item: function to call on each item retrieved
103 * @resync: function to resync the iterator
104 * @free: function to free the iterator
106 * Create a new iterator. This function is mainly used for objects
107 * implementing the next/resync/free function to iterate a data structure.
109 * For each item retrieved, the @item function is called with the lock
110 * held. The @free function is called when the iterator is freed.
112 * Returns: the new #GstIterator.
117 gst_iterator_new (guint size,
120 guint32 * master_cookie,
121 GstIteratorNextFunction next,
122 GstIteratorItemFunction item,
123 GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
127 g_return_val_if_fail (size >= sizeof (GstIterator), NULL);
128 g_return_val_if_fail (g_type_qname (type) != 0, NULL);
129 g_return_val_if_fail (master_cookie != NULL, NULL);
130 g_return_val_if_fail (next != NULL, NULL);
131 g_return_val_if_fail (resync != NULL, NULL);
132 g_return_val_if_fail (free != NULL, NULL);
134 result = g_malloc (size);
135 gst_iterator_init (result, type, lock, master_cookie, next, item, resync,
144 typedef struct _GstListIterator
146 GstIterator iterator;
149 GList *list; /* pointer in list */
150 GstIteratorDisposeFunction freefunc;
153 static GstIteratorResult
154 gst_list_iterator_next (GstListIterator * it, gpointer * elem)
156 if (it->list == NULL)
157 return GST_ITERATOR_DONE;
159 *elem = it->list->data;
160 it->list = g_list_next (it->list);
162 return GST_ITERATOR_OK;
166 gst_list_iterator_resync (GstListIterator * it)
168 it->list = *it->orig;
172 gst_list_iterator_free (GstListIterator * it)
175 it->freefunc (it->owner);
181 * gst_iterator_new_list:
182 * @type: #GType of elements
183 * @lock: pointer to a #GMutex protecting the list.
184 * @master_cookie: pointer to a guint32 that is incremented when the list
186 * @list: pointer to the list
187 * @owner: object owning the list
188 * @item: function to call for each item
189 * @free: function to call when the iterator is freed
191 * Create a new iterator designed for iterating @list.
193 * The list you iterate is usually part of a data structure @owner and is
194 * protected with @lock.
196 * The iterator will use @lock to retrieve the next item of the list and it
197 * will then call the @item function before releasing @lock again.
199 * The @item function usualy makes sure that the item remains alive while
200 * @lock is released and the application is using the item. The application is
201 * responsible for freeing/unreffing the item after usage as explained in
202 * gst_iterator_next().
204 * When a concurrent update to the list is performed, usually by @owner while
205 * holding @lock, @master_cookie will be updated. The iterator implementation
206 * will notice the update of the cookie and will return %GST_ITERATOR_RESYNC to
207 * the user of the iterator in the next call to gst_iterator_next().
209 * @owner will be passed to the @free function when the iterator is freed.
211 * Returns: the new #GstIterator for @list.
216 gst_iterator_new_list (GType type,
218 guint32 * master_cookie,
221 GstIteratorItemFunction item, GstIteratorDisposeFunction free)
223 GstListIterator *result;
225 /* no need to lock, nothing can change here */
226 result = (GstListIterator *) gst_iterator_new (sizeof (GstListIterator),
230 (GstIteratorNextFunction) gst_list_iterator_next,
231 (GstIteratorItemFunction) item,
232 (GstIteratorResyncFunction) gst_list_iterator_resync,
233 (GstIteratorFreeFunction) gst_list_iterator_free);
235 result->owner = owner;
237 result->list = *list;
238 result->freefunc = free;
240 return GST_ITERATOR (result);
244 gst_iterator_pop (GstIterator * it)
247 gst_iterator_free (it->pushed);
254 * @it: The #GstIterator to iterate
255 * @elem: pointer to hold next element
257 * Get the next item from the iterator in @elem.
259 * Only when this function returns %GST_ITERATOR_OK, @elem will contain a valid
260 * value. For iterators that return refcounted objects, the returned object
261 * will have its refcount increased and should therefore be unreffed after
264 * When this function returns %GST_ITERATOR_DONE, no more elements can be
265 * retrieved from @it.
267 * A return value of %GST_ITERATOR_RESYNC indicates that the element list was
268 * concurrently updated. The user of @it should call gst_iterator_resync() to
269 * get the newly updated list.
271 * A return value of %GST_ITERATOR_ERROR indicates an unrecoverable fatal error.
273 * Returns: The result of the iteration. Unref @elem after usage if this
274 * is a refcounted object.
279 gst_iterator_next (GstIterator * it, gpointer * elem)
281 GstIteratorResult result;
283 g_return_val_if_fail (it != NULL, GST_ITERATOR_ERROR);
284 g_return_val_if_fail (elem != NULL, GST_ITERATOR_ERROR);
288 result = gst_iterator_next (it->pushed, elem);
289 if (result == GST_ITERATOR_DONE) {
290 /* we are done with this iterator, pop it and
291 * fallthrough iterating the main iterator again. */
292 gst_iterator_pop (it);
298 if (G_LIKELY (it->lock))
299 g_mutex_lock (it->lock);
301 if (G_UNLIKELY (*it->master_cookie != it->cookie)) {
302 result = GST_ITERATOR_RESYNC;
306 result = it->next (it, elem);
307 if (result == GST_ITERATOR_OK && it->item) {
308 GstIteratorItem itemres;
310 itemres = it->item (it, *elem);
312 case GST_ITERATOR_ITEM_SKIP:
313 if (G_LIKELY (it->lock))
314 g_mutex_unlock (it->lock);
316 case GST_ITERATOR_ITEM_END:
317 result = GST_ITERATOR_DONE;
319 case GST_ITERATOR_ITEM_PASS:
325 if (G_LIKELY (it->lock))
326 g_mutex_unlock (it->lock);
332 * gst_iterator_resync:
333 * @it: The #GstIterator to resync
335 * Resync the iterator. this function is mostly called
336 * after gst_iterator_next() returned %GST_ITERATOR_RESYNC.
338 * When an iterator was pushed on @it, it will automatically be popped again
339 * with this function.
344 gst_iterator_resync (GstIterator * it)
346 g_return_if_fail (it != NULL);
348 gst_iterator_pop (it);
350 if (G_LIKELY (it->lock))
351 g_mutex_lock (it->lock);
353 it->cookie = *it->master_cookie;
354 if (G_LIKELY (it->lock))
355 g_mutex_unlock (it->lock);
360 * @it: The #GstIterator to free
367 gst_iterator_free (GstIterator * it)
369 g_return_if_fail (it != NULL);
371 gst_iterator_pop (it);
378 * @it: The #GstIterator to use
379 * @other: The #GstIterator to push
381 * Pushes @other iterator onto @it. All calls performed on @it are
382 * forwarded to @other. If @other returns %GST_ITERATOR_DONE, it is
383 * popped again and calls are handled by @it again.
385 * This function is mainly used by objects implementing the iterator
386 * next function to recurse into substructures.
388 * When gst_iterator_resync() is called on @it, @other will automatically be
394 gst_iterator_push (GstIterator * it, GstIterator * other)
396 g_return_if_fail (it != NULL);
397 g_return_if_fail (other != NULL);
402 typedef struct _GstIteratorFilter
404 GstIterator iterator;
411 static GstIteratorResult
412 filter_next (GstIteratorFilter * it, gpointer * elem)
414 GstIteratorResult result = GST_ITERATOR_ERROR;
415 gboolean done = FALSE;
419 while (G_LIKELY (!done)) {
422 result = gst_iterator_next (it->slave, &item);
424 case GST_ITERATOR_OK:
425 if (G_LIKELY (GST_ITERATOR (it)->lock))
426 g_mutex_unlock (GST_ITERATOR (it)->lock);
427 if (it->func (item, it->user_data) == 0) {
431 if (G_LIKELY (GST_ITERATOR (it)->lock))
432 g_mutex_lock (GST_ITERATOR (it)->lock);
434 case GST_ITERATOR_RESYNC:
435 case GST_ITERATOR_DONE:
439 g_assert_not_reached ();
447 filter_resync (GstIteratorFilter * it)
449 gst_iterator_resync (it->slave);
453 filter_uninit (GstIteratorFilter * it)
455 it->slave->lock = GST_ITERATOR (it)->lock;
459 filter_free (GstIteratorFilter * it)
462 gst_iterator_free (it->slave);
467 * gst_iterator_filter:
468 * @it: The #GstIterator to filter
469 * @func: the compare function to select elements
470 * @user_data: user data passed to the compare function
472 * Create a new iterator from an existing iterator. The new iterator
473 * will only return those elements that match the given compare function @func.
474 * @func should return 0 for elements that should be included
477 * When this iterator is freed, @it will also be freed.
479 * Returns: a new #GstIterator.
484 gst_iterator_filter (GstIterator * it, GCompareFunc func, gpointer user_data)
486 GstIteratorFilter *result;
488 g_return_val_if_fail (it != NULL, NULL);
489 g_return_val_if_fail (func != NULL, NULL);
491 result = (GstIteratorFilter *) gst_iterator_new (sizeof (GstIteratorFilter),
492 it->type, it->lock, it->master_cookie,
493 (GstIteratorNextFunction) filter_next,
494 (GstIteratorItemFunction) NULL,
495 (GstIteratorResyncFunction) filter_resync,
496 (GstIteratorFreeFunction) filter_free);
499 result->user_data = user_data;
502 return GST_ITERATOR (result);
507 * @it: The #GstIterator to fold over
508 * @func: the fold function
509 * @ret: the seed value passed to the fold function
510 * @user_data: user data passed to the fold function
512 * Folds @func over the elements of @iter. That is to say, @func will be called
513 * as @func (object, @ret, @user_data) for each object in @it. The normal use
514 * of this procedure is to accumulate the results of operating on the objects in
515 * @ret. If object is a refcounted object its refcount will be increased
516 * before @func is called, and it should be unrefed after use in @func.
518 * This procedure can be used (and is used internally) to implement the
519 * gst_iterator_foreach() and gst_iterator_find_custom() operations.
521 * The fold will proceed as long as @func returns TRUE. When the iterator has no
522 * more arguments, %GST_ITERATOR_DONE will be returned. If @func returns FALSE,
523 * the fold will stop, and %GST_ITERATOR_OK will be returned. Errors or resyncs
524 * will cause fold to return %GST_ITERATOR_ERROR or %GST_ITERATOR_RESYNC as
527 * The iterator will not be freed.
529 * Returns: A #GstIteratorResult, as described above.
534 gst_iterator_fold (GstIterator * it, GstIteratorFoldFunction func,
535 GValue * ret, gpointer user_data)
538 GstIteratorResult result;
541 result = gst_iterator_next (it, &item);
543 case GST_ITERATOR_OK:
544 /* FIXME: is there a way to ref/unref items? */
545 if (!func (item, ret, user_data))
549 case GST_ITERATOR_RESYNC:
550 case GST_ITERATOR_ERROR:
552 case GST_ITERATOR_DONE:
568 foreach_fold_func (gpointer item, GValue * unused, ForeachFoldData * data)
570 data->func (item, data->user_data);
575 * gst_iterator_foreach:
576 * @it: The #GstIterator to iterate
577 * @func: the function to call for each element.
578 * @user_data: user data passed to the function
580 * Iterate over all element of @it and call the given function @func for
581 * each element. As in gst_iterator_fold(), the refcount of a refcounted
582 * object will be increased before @func is called, and should be unrefed
585 * Returns: the result call to gst_iterator_fold(). The iterator will not be
591 gst_iterator_foreach (GstIterator * it, GFunc func, gpointer user_data)
593 ForeachFoldData data;
596 data.user_data = user_data;
598 return gst_iterator_fold (it, (GstIteratorFoldFunction) foreach_fold_func,
606 } FindCustomFoldData;
609 find_custom_fold_func (gpointer item, GValue * ret, FindCustomFoldData * data)
611 if (data->func (item, data->user_data) == 0) {
612 g_value_set_pointer (ret, item);
620 * gst_iterator_find_custom:
621 * @it: The #GstIterator to iterate
622 * @func: the compare function to use
623 * @user_data: user data passed to the compare function
625 * Find the first element in @it that matches the compare function @func.
626 * @func should return 0 when the element is found. As in gst_iterator_fold(),
627 * the refcount of a refcounted object will be increased before @func is
628 * called, and should be unrefed after use.
630 * The iterator will not be freed.
632 * This function will return NULL if an error or resync happened to
635 * Returns: The element in the iterator that matches the compare
636 * function or NULL when no element matched.
641 gst_iterator_find_custom (GstIterator * it, GCompareFunc func,
645 GstIteratorResult res;
646 FindCustomFoldData data;
648 g_value_init (&ret, G_TYPE_POINTER);
650 data.user_data = user_data;
652 /* FIXME, we totally ignore RESYNC and return NULL so that the
653 * app does not know if the element was not found or a resync happened */
655 gst_iterator_fold (it, (GstIteratorFoldFunction) find_custom_fold_func,
658 /* no need to unset, it's just a pointer */
659 return g_value_get_pointer (&ret);
666 GstCopyFunction copy;
669 } GstSingleObjectIterator;
671 static guint32 _single_object_dummy_cookie = 0;
673 static GstIteratorResult
674 gst_single_object_iterator_iterator_next (GstSingleObjectIterator * it,
677 if (it->visited || !it->object) {
679 return GST_ITERATOR_DONE;
682 *result = it->copy (it->object);
683 return GST_ITERATOR_OK;
687 gst_single_object_iterator_resync (GstSingleObjectIterator * it)
693 gst_single_object_iterator_free (GstSingleObjectIterator * it)
696 it->free (it->object);
702 * @type: #GType of the passed object
703 * @object: object that this iterator should return
704 * @copy: Function that returns a copy of @object or increases its refcount
705 * @free: Function to be called for freeing @object
707 * This #GstIterator is a convenient iterator for the common
708 * case where a #GstIterator needs to be returned but only
709 * a single object has the be considered. This happens often
710 * for the #GstPadIterIntLinkFunction.
716 gst_iterator_new_single (GType type, gpointer object, GstCopyFunction copy,
719 GstSingleObjectIterator *result;
721 g_return_val_if_fail (copy != NULL, NULL);
722 g_return_val_if_fail (free != NULL, NULL);
724 result = (GstSingleObjectIterator *)
725 gst_iterator_new (sizeof (GstSingleObjectIterator),
726 G_TYPE_FROM_INSTANCE (object), NULL, &_single_object_dummy_cookie,
727 (GstIteratorNextFunction) gst_single_object_iterator_iterator_next, NULL,
728 (GstIteratorResyncFunction) gst_single_object_iterator_resync,
729 (GstIteratorFreeFunction) gst_single_object_iterator_free);
731 result->object = (object) ? copy (object) : NULL;
734 result->visited = FALSE;
736 return (GstIterator *) result;