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.
23 * @short_description: Object to retrieve multiple elements in a threadsafe
25 * @see_also: #GstElement, #GstBin
27 * A GstIterator is used to retrieve multiple objects from another object in
30 * Various GStreamer objects provide access to their internal structures using
34 #include "gst_private.h"
35 #include <gst/gstiterator.h>
38 gst_iterator_init (GstIterator * it,
41 guint32 * master_cookie,
42 GstIteratorNextFunction next,
43 GstIteratorItemFunction item,
44 GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
48 it->master_cookie = master_cookie;
49 it->cookie = *master_cookie;
59 * @size: the size of the iterator structure
60 * @type: #GType of children
61 * @lock: pointer to a #GMutex.
62 * @master_cookie: pointer to a guint32 to protect the iterated object.
63 * @next: function to get next item
64 * @item: function to call on each item retrieved
65 * @resync: function to resync the iterator
66 * @free: function to free the iterator
68 * Create a new iterator. This function is mainly used for objects
69 * implementing the next/resync/free function to iterate a data structure.
71 * For each item retrieved, the @item function is called with the lock
72 * held. The @free function is called when the iterator is freed.
74 * Returns: the new #GstIterator.
79 gst_iterator_new (guint size,
82 guint32 * master_cookie,
83 GstIteratorNextFunction next,
84 GstIteratorItemFunction item,
85 GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
89 g_return_val_if_fail (size >= sizeof (GstIterator), NULL);
90 g_return_val_if_fail (master_cookie != NULL, NULL);
91 g_return_val_if_fail (next != NULL, NULL);
92 g_return_val_if_fail (resync != NULL, NULL);
93 g_return_val_if_fail (free != NULL, NULL);
95 result = g_malloc (size);
96 gst_iterator_init (result, type, lock, master_cookie, next, item, resync,
105 typedef struct _GstListIterator
107 GstIterator iterator;
110 GList *list; /* pointer in list */
112 GstIteratorDisposeFunction freefunc;
115 static GstIteratorResult
116 gst_list_iterator_next (GstListIterator * it, gpointer * elem)
118 if (it->list == NULL)
119 return GST_ITERATOR_DONE;
121 *elem = it->list->data;
122 it->list = g_list_next (it->list);
124 return GST_ITERATOR_OK;
128 gst_list_iterator_resync (GstListIterator * it)
130 it->list = *it->orig;
134 gst_list_iterator_free (GstListIterator * it)
137 it->freefunc (it->owner);
143 * gst_iterator_new_list:
144 * @type: #GType of elements
145 * @lock: pointer to a #GMutex protecting the list.
146 * @master_cookie: pointer to a guint32 to protect the list.
147 * @list: pointer to the list
148 * @owner: object owning the list
149 * @item: function to call for each item
150 * @free: function to call when the iterator is freed
152 * Create a new iterator designed for iterating @list.
154 * Returns: the new #GstIterator for @list.
159 gst_iterator_new_list (GType type,
161 guint32 * master_cookie,
164 GstIteratorItemFunction item, GstIteratorDisposeFunction free)
166 GstListIterator *result;
168 /* no need to lock, nothing can change here */
169 result = (GstListIterator *) gst_iterator_new (sizeof (GstListIterator),
173 (GstIteratorNextFunction) gst_list_iterator_next,
174 (GstIteratorItemFunction) item,
175 (GstIteratorResyncFunction) gst_list_iterator_resync,
176 (GstIteratorFreeFunction) gst_list_iterator_free);
178 result->owner = owner;
180 result->list = *list;
181 result->freefunc = free;
183 return GST_ITERATOR (result);
187 gst_iterator_pop (GstIterator * it)
190 gst_iterator_free (it->pushed);
197 * @it: The #GstIterator to iterate
198 * @elem: pointer to hold next element
200 * Get the next item from the iterator.
202 * Returns: The result of the iteration.
207 gst_iterator_next (GstIterator * it, gpointer * elem)
209 GstIteratorResult result;
211 g_return_val_if_fail (it != NULL, GST_ITERATOR_ERROR);
212 g_return_val_if_fail (elem != NULL, GST_ITERATOR_ERROR);
216 result = gst_iterator_next (it->pushed, elem);
217 if (result == GST_ITERATOR_DONE) {
218 /* we are done with this iterator, pop it and
219 * fallthrough iterating the main iterator again. */
220 gst_iterator_pop (it);
226 if (G_LIKELY (it->lock))
227 g_mutex_lock (it->lock);
229 if (G_UNLIKELY (*it->master_cookie != it->cookie)) {
230 result = GST_ITERATOR_RESYNC;
234 result = it->next (it, elem);
235 if (result == GST_ITERATOR_OK && it->item) {
236 GstIteratorItem itemres;
238 itemres = it->item (it, *elem);
240 case GST_ITERATOR_ITEM_SKIP:
241 if (G_LIKELY (it->lock))
242 g_mutex_unlock (it->lock);
244 case GST_ITERATOR_ITEM_END:
245 result = GST_ITERATOR_DONE;
247 case GST_ITERATOR_ITEM_PASS:
253 if (G_LIKELY (it->lock))
254 g_mutex_unlock (it->lock);
260 * gst_iterator_resync:
261 * @it: The #GstIterator to resync
263 * Resync the iterator. this function is mostly called
264 * after #gst_iterator_next() returned #GST_ITERATOR_RESYNC.
269 gst_iterator_resync (GstIterator * it)
271 g_return_if_fail (it != NULL);
273 gst_iterator_pop (it);
275 if (G_LIKELY (it->lock))
276 g_mutex_lock (it->lock);
278 it->cookie = *it->master_cookie;
279 if (G_LIKELY (it->lock))
280 g_mutex_unlock (it->lock);
285 * @it: The #GstIterator to free
292 gst_iterator_free (GstIterator * it)
294 g_return_if_fail (it != NULL);
296 gst_iterator_pop (it);
303 * @it: The #GstIterator to use
304 * @other: The #GstIterator to push
306 * Pushes @other iterator onto @it. All calls performed on @it are
307 * forwarded tot @other. If @other returns #GST_ITERATOR_DONE, it is
308 * popped again and calls are handled by @it again.
310 * This function is mainly used by objects implementing the iterator
311 * next function to recurse into substructures.
316 gst_iterator_push (GstIterator * it, GstIterator * other)
318 g_return_if_fail (it != NULL);
319 g_return_if_fail (other != NULL);
324 typedef struct _GstIteratorFilter
326 GstIterator iterator;
333 static GstIteratorResult
334 filter_next (GstIteratorFilter * it, gpointer * elem)
336 GstIteratorResult result = GST_ITERATOR_ERROR;
337 gboolean done = FALSE;
341 while (G_LIKELY (!done)) {
344 result = gst_iterator_next (it->slave, &item);
346 case GST_ITERATOR_OK:
347 if (G_LIKELY (GST_ITERATOR (it)->lock))
348 g_mutex_unlock (GST_ITERATOR (it)->lock);
349 if (it->func (item, it->user_data) == 0) {
353 if (G_LIKELY (GST_ITERATOR (it)->lock))
354 g_mutex_lock (GST_ITERATOR (it)->lock);
356 case GST_ITERATOR_RESYNC:
357 case GST_ITERATOR_DONE:
361 g_assert_not_reached ();
369 filter_resync (GstIteratorFilter * it)
371 gst_iterator_resync (it->slave);
375 filter_uninit (GstIteratorFilter * it)
377 it->slave->lock = GST_ITERATOR (it)->lock;
381 filter_free (GstIteratorFilter * it)
384 gst_iterator_free (it->slave);
389 * gst_iterator_filter:
390 * @it: The #GstIterator to filter
391 * @user_data: user data passed to the compare function
392 * @func: the compare function to select elements
394 * Create a new iterator from an existing iterator. The new iterator
395 * will only return those elements that match the given compare function.
396 * The GCompareFunc should return 0 for elements that should be included
399 * When this iterator is freed, @it will also be freed.
401 * Returns: a new #GstIterator.
406 gst_iterator_filter (GstIterator * it, GCompareFunc func, gpointer user_data)
408 GstIteratorFilter *result;
410 g_return_val_if_fail (it != NULL, NULL);
411 g_return_val_if_fail (func != NULL, NULL);
413 result = (GstIteratorFilter *) gst_iterator_new (sizeof (GstIteratorFilter),
414 it->type, it->lock, it->master_cookie,
415 (GstIteratorNextFunction) filter_next,
416 (GstIteratorItemFunction) NULL,
417 (GstIteratorResyncFunction) filter_resync,
418 (GstIteratorFreeFunction) filter_free);
421 result->user_data = user_data;
424 return GST_ITERATOR (result);
429 * @iter: The #GstIterator to fold over
430 * @func: the fold function
431 * @ret: the seed value passed to the fold function
432 * @user_data: user data passed to the fold function
434 * Folds @func over the elements of @iter. That is to say, @proc will be called
435 * as @proc (object, @ret, @user_data) for each object in @iter. The normal use
436 * of this procedure is to accumulate the results of operating on the objects in
439 * This procedure can be used (and is used internally) to implement the foreach
440 * and find_custom operations.
442 * The fold will proceed as long as @func returns TRUE. When the iterator has no
443 * more arguments, GST_ITERATOR_DONE will be returned. If @func returns FALSE,
444 * the fold will stop, and GST_ITERATOR_OK will be returned. Errors or resyncs
445 * will cause fold to return GST_ITERATOR_ERROR or GST_ITERATOR_RESYNC as
448 * The iterator will not be freed.
450 * Returns: A #GstIteratorResult, as described above.
455 gst_iterator_fold (GstIterator * iter, GstIteratorFoldFunction func,
456 GValue * ret, gpointer user_data)
459 GstIteratorResult result;
462 result = gst_iterator_next (iter, &item);
464 case GST_ITERATOR_OK:
465 /* fixme: is there a way to ref/unref items? */
466 if (!func (item, ret, user_data))
470 case GST_ITERATOR_RESYNC:
471 case GST_ITERATOR_ERROR:
473 case GST_ITERATOR_DONE:
489 foreach_fold_func (gpointer item, GValue * unused, ForeachFoldData * data)
491 data->func (item, data->user_data);
496 * gst_iterator_foreach:
497 * @iter: The #GstIterator to iterate
498 * @func: the function to call for each element.
499 * @user_data: user data passed to the function
501 * Iterate over all element of @it and call the given function for
504 * Returns: the result call to gst_iterator_fold(). The iterator will not be
510 gst_iterator_foreach (GstIterator * iter, GFunc func, gpointer user_data)
512 ForeachFoldData data;
515 data.user_data = user_data;
517 return gst_iterator_fold (iter, (GstIteratorFoldFunction) foreach_fold_func,
525 } FindCustomFoldData;
528 find_custom_fold_func (gpointer item, GValue * ret, FindCustomFoldData * data)
530 if (data->func (item, data->user_data) == 0) {
531 g_value_set_pointer (ret, item);
539 * gst_iterator_find_custom:
540 * @it: The #GstIterator to iterate
541 * @user_data: user data passed to the compare function
542 * @func: the compare function to use
544 * Find the first element in @it that matches the compare function.
545 * The compare function should return 0 when the element is found.
547 * The iterator will not be freed.
549 * Returns: The element in the iterator that matches the compare
550 * function or NULL when no element matched.
555 gst_iterator_find_custom (GstIterator * iter, GCompareFunc func,
559 GstIteratorResult res;
560 FindCustomFoldData data;
562 g_value_init (&ret, G_TYPE_POINTER);
564 data.user_data = user_data;
567 gst_iterator_fold (iter, (GstIteratorFoldFunction) find_custom_fold_func,
570 /* no need to unset, it's just a pointer */
571 return g_value_get_pointer (&ret);