]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/blob - gst/gstiterator.c
gststructure: early out when we know a value cannot be a subset
[glsdk/gstreamer0-10.git] / gst / gstiterator.c
1 /* GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  *
4  * gstiterator.h: Base class for iterating datastructures.
5  *
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.
10  *
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.
15  *
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.
20  */
22 /**
23  * SECTION:gstiterator
24  * @short_description: Object to retrieve multiple elements in a threadsafe
25  * way.
26  * @see_also: #GstElement, #GstBin
27  *
28  * A GstIterator is used to retrieve multiple objects from another object in
29  * a threadsafe way.
30  *
31  * Various GStreamer objects provide access to their internal structures using
32  * an iterator.
33  *
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.
37  *
38  * The basic use pattern of an iterator is as follows:
39  *
40  * <example>
41  * <title>Using an iterator</title>
42  *   <programlisting>
43  *    it = _get_iterator(object);
44  *    done = FALSE;
45  *    while (!done) {
46  *      switch (gst_iterator_next (it, &amp;item)) {
47  *        case GST_ITERATOR_OK:
48  *          ... use/change item here...
49  *          gst_object_unref (item);
50  *          break;
51  *        case GST_ITERATOR_RESYNC:
52  *          ...rollback changes to items...
53  *          gst_iterator_resync (it);
54  *          break;
55  *        case GST_ITERATOR_ERROR:
56  *          ...wrong parameters were given...
57  *          done = TRUE;
58  *          break;
59  *        case GST_ITERATOR_DONE:
60  *          done = TRUE;
61  *          break;
62  *      }
63  *    }
64  *    gst_iterator_free (it);
65  *   </programlisting>
66  * </example>
67  *
68  * Last reviewed on 2009-06-16 (0.10.24)
69  */
71 #include "gst_private.h"
72 #include <gst/gstiterator.h>
74 /* FIXME 0.11: Store the size inside the iterator, use GSlice for allocation
75  * and let gst_iterator_free() free the memory while the free-func only frees
76  * additional resources (maybe call it finalize?).
77  */
79 static void
80 gst_iterator_init (GstIterator * it,
81     GType type,
82     GMutex * lock,
83     guint32 * master_cookie,
84     GstIteratorNextFunction next,
85     GstIteratorItemFunction item,
86     GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
87 {
88   it->type = type;
89   it->lock = lock;
90   it->master_cookie = master_cookie;
91   it->cookie = *master_cookie;
92   it->next = next;
93   it->item = item;
94   it->resync = resync;
95   it->free = free;
96   it->pushed = NULL;
97 }
99 /**
100  * gst_iterator_new:
101  * @size: the size of the iterator structure
102  * @type: #GType of children
103  * @lock: pointer to a #GMutex.
104  * @master_cookie: pointer to a guint32 that is changed when the items in the
105  *    iterator changed.
106  * @next: function to get next item
107  * @item: function to call on each item retrieved
108  * @resync: function to resync the iterator
109  * @free: function to free the iterator
110  *
111  * Create a new iterator. This function is mainly used for objects
112  * implementing the next/resync/free function to iterate a data structure.
113  *
114  * For each item retrieved, the @item function is called with the lock
115  * held. The @free function is called when the iterator is freed.
116  *
117  * Returns: the new #GstIterator.
118  *
119  * MT safe.
120  */
121 GstIterator *
122 gst_iterator_new (guint size,
123     GType type,
124     GMutex * lock,
125     guint32 * master_cookie,
126     GstIteratorNextFunction next,
127     GstIteratorItemFunction item,
128     GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
130   GstIterator *result;
132   g_return_val_if_fail (size >= sizeof (GstIterator), NULL);
133   g_return_val_if_fail (g_type_qname (type) != 0, NULL);
134   g_return_val_if_fail (master_cookie != NULL, NULL);
135   g_return_val_if_fail (next != NULL, NULL);
136   g_return_val_if_fail (resync != NULL, NULL);
137   g_return_val_if_fail (free != NULL, NULL);
139   result = g_malloc (size);
140   gst_iterator_init (result, type, lock, master_cookie, next, item, resync,
141       free);
143   return result;
146 /*
147  * list iterator
148  */
149 typedef struct _GstListIterator
151   GstIterator iterator;
152   gpointer owner;
153   GList **orig;
154   GList *list;                  /* pointer in list */
155   GstIteratorDisposeFunction freefunc;
156 } GstListIterator;
158 static GstIteratorResult
159 gst_list_iterator_next (GstListIterator * it, gpointer * elem)
161   if (it->list == NULL)
162     return GST_ITERATOR_DONE;
164   *elem = it->list->data;
165   it->list = g_list_next (it->list);
167   return GST_ITERATOR_OK;
170 static void
171 gst_list_iterator_resync (GstListIterator * it)
173   it->list = *it->orig;
176 static void
177 gst_list_iterator_free (GstListIterator * it)
179   if (it->freefunc) {
180     it->freefunc (it->owner);
181   }
182   g_free (it);
185 /**
186  * gst_iterator_new_list:
187  * @type: #GType of elements
188  * @lock: pointer to a #GMutex protecting the list.
189  * @master_cookie: pointer to a guint32 that is incremented when the list
190  *     is changed.
191  * @list: pointer to the list
192  * @owner: object owning the list
193  * @item: function to call for each item
194  * @free: function to call when the iterator is freed
195  *
196  * Create a new iterator designed for iterating @list.
197  *
198  * The list you iterate is usually part of a data structure @owner and is
199  * protected with @lock. 
200  *
201  * The iterator will use @lock to retrieve the next item of the list and it
202  * will then call the @item function before releasing @lock again.
203  *
204  * The @item function usualy makes sure that the item remains alive while
205  * @lock is released and the application is using the item. The application is
206  * responsible for freeing/unreffing the item after usage as explained in
207  * gst_iterator_next().
208  *
209  * When a concurrent update to the list is performed, usually by @owner while
210  * holding @lock, @master_cookie will be updated. The iterator implementation
211  * will notice the update of the cookie and will return %GST_ITERATOR_RESYNC to
212  * the user of the iterator in the next call to gst_iterator_next().
213  *
214  * @owner will be passed to the @free function when the iterator is freed.
215  *
216  * Returns: the new #GstIterator for @list.
217  *
218  * MT safe.
219  */
220 GstIterator *
221 gst_iterator_new_list (GType type,
222     GMutex * lock,
223     guint32 * master_cookie,
224     GList ** list,
225     gpointer owner,
226     GstIteratorItemFunction item, GstIteratorDisposeFunction free)
228   GstListIterator *result;
230   /* no need to lock, nothing can change here */
231   result = (GstListIterator *) gst_iterator_new (sizeof (GstListIterator),
232       type,
233       lock,
234       master_cookie,
235       (GstIteratorNextFunction) gst_list_iterator_next,
236       (GstIteratorItemFunction) item,
237       (GstIteratorResyncFunction) gst_list_iterator_resync,
238       (GstIteratorFreeFunction) gst_list_iterator_free);
240   result->owner = owner;
241   result->orig = list;
242   result->list = *list;
243   result->freefunc = free;
245   return GST_ITERATOR (result);
248 static void
249 gst_iterator_pop (GstIterator * it)
251   if (it->pushed) {
252     gst_iterator_free (it->pushed);
253     it->pushed = NULL;
254   }
257 /**
258  * gst_iterator_next:
259  * @it: The #GstIterator to iterate
260  * @elem: pointer to hold next element
261  *
262  * Get the next item from the iterator in @elem. 
263  *
264  * Only when this function returns %GST_ITERATOR_OK, @elem will contain a valid
265  * value. For iterators that return refcounted objects, the returned object
266  * will have its refcount increased and should therefore be unreffed after
267  * usage.
268  *
269  * When this function returns %GST_ITERATOR_DONE, no more elements can be
270  * retrieved from @it.
271  *
272  * A return value of %GST_ITERATOR_RESYNC indicates that the element list was
273  * concurrently updated. The user of @it should call gst_iterator_resync() to
274  * get the newly updated list. 
275  *
276  * A return value of %GST_ITERATOR_ERROR indicates an unrecoverable fatal error.
277  *
278  * Returns: The result of the iteration. Unref @elem after usage if this
279  * is a refcounted object.
280  *
281  * MT safe.
282  */
283 GstIteratorResult
284 gst_iterator_next (GstIterator * it, gpointer * elem)
286   GstIteratorResult result;
288   g_return_val_if_fail (it != NULL, GST_ITERATOR_ERROR);
289   g_return_val_if_fail (elem != NULL, GST_ITERATOR_ERROR);
291 restart:
292   if (it->pushed) {
293     result = gst_iterator_next (it->pushed, elem);
294     if (result == GST_ITERATOR_DONE) {
295       /* we are done with this iterator, pop it and
296        * fallthrough iterating the main iterator again. */
297       gst_iterator_pop (it);
298     } else {
299       return result;
300     }
301   }
303   if (G_LIKELY (it->lock))
304     g_mutex_lock (it->lock);
306   if (G_UNLIKELY (*it->master_cookie != it->cookie)) {
307     result = GST_ITERATOR_RESYNC;
308     goto done;
309   }
311   result = it->next (it, elem);
312   if (result == GST_ITERATOR_OK && it->item) {
313     GstIteratorItem itemres;
315     itemres = it->item (it, *elem);
316     switch (itemres) {
317       case GST_ITERATOR_ITEM_SKIP:
318         if (G_LIKELY (it->lock))
319           g_mutex_unlock (it->lock);
320         goto restart;
321       case GST_ITERATOR_ITEM_END:
322         result = GST_ITERATOR_DONE;
323         break;
324       case GST_ITERATOR_ITEM_PASS:
325         break;
326     }
327   }
329 done:
330   if (G_LIKELY (it->lock))
331     g_mutex_unlock (it->lock);
333   return result;
336 /**
337  * gst_iterator_resync:
338  * @it: The #GstIterator to resync
339  *
340  * Resync the iterator. this function is mostly called
341  * after gst_iterator_next() returned %GST_ITERATOR_RESYNC.
342  *
343  * When an iterator was pushed on @it, it will automatically be popped again
344  * with this function.
345  *
346  * MT safe.
347  */
348 void
349 gst_iterator_resync (GstIterator * it)
351   g_return_if_fail (it != NULL);
353   gst_iterator_pop (it);
355   if (G_LIKELY (it->lock))
356     g_mutex_lock (it->lock);
357   it->resync (it);
358   it->cookie = *it->master_cookie;
359   if (G_LIKELY (it->lock))
360     g_mutex_unlock (it->lock);
363 /**
364  * gst_iterator_free:
365  * @it: The #GstIterator to free
366  *
367  * Free the iterator.
368  *
369  * MT safe.
370  */
371 void
372 gst_iterator_free (GstIterator * it)
374   g_return_if_fail (it != NULL);
376   gst_iterator_pop (it);
378   it->free (it);
381 /**
382  * gst_iterator_push:
383  * @it: The #GstIterator to use
384  * @other: The #GstIterator to push
385  *
386  * Pushes @other iterator onto @it. All calls performed on @it are
387  * forwarded to @other. If @other returns %GST_ITERATOR_DONE, it is
388  * popped again and calls are handled by @it again.
389  *
390  * This function is mainly used by objects implementing the iterator
391  * next function to recurse into substructures.
392  *
393  * When gst_iterator_resync() is called on @it, @other will automatically be
394  * popped.
395  *
396  * MT safe.
397  */
398 void
399 gst_iterator_push (GstIterator * it, GstIterator * other)
401   g_return_if_fail (it != NULL);
402   g_return_if_fail (other != NULL);
404   it->pushed = other;
407 typedef struct _GstIteratorFilter
409   GstIterator iterator;
410   GstIterator *slave;
412   GCompareFunc func;
413   gpointer user_data;
414 } GstIteratorFilter;
416 static GstIteratorResult
417 filter_next (GstIteratorFilter * it, gpointer * elem)
419   GstIteratorResult result = GST_ITERATOR_ERROR;
420   gboolean done = FALSE;
422   *elem = NULL;
424   while (G_LIKELY (!done)) {
425     gpointer item;
427     result = gst_iterator_next (it->slave, &item);
428     switch (result) {
429       case GST_ITERATOR_OK:
430         if (G_LIKELY (GST_ITERATOR (it)->lock))
431           g_mutex_unlock (GST_ITERATOR (it)->lock);
432         if (it->func (item, it->user_data) == 0) {
433           *elem = item;
434           done = TRUE;
435         }
436         if (G_LIKELY (GST_ITERATOR (it)->lock))
437           g_mutex_lock (GST_ITERATOR (it)->lock);
438         break;
439       case GST_ITERATOR_RESYNC:
440       case GST_ITERATOR_DONE:
441         done = TRUE;
442         break;
443       default:
444         g_assert_not_reached ();
445         break;
446     }
447   }
448   return result;
451 static void
452 filter_resync (GstIteratorFilter * it)
454   gst_iterator_resync (it->slave);
457 static void
458 filter_uninit (GstIteratorFilter * it)
460   it->slave->lock = GST_ITERATOR (it)->lock;
463 static void
464 filter_free (GstIteratorFilter * it)
466   filter_uninit (it);
467   gst_iterator_free (it->slave);
468   g_free (it);
471 /**
472  * gst_iterator_filter:
473  * @it: The #GstIterator to filter
474  * @func: (scope call): the compare function to select elements
475  * @user_data: (closure): user data passed to the compare function
476  *
477  * Create a new iterator from an existing iterator. The new iterator
478  * will only return those elements that match the given compare function @func.
479  * @func should return 0 for elements that should be included
480  * in the iterator.
481  *
482  * When this iterator is freed, @it will also be freed.
483  *
484  * Returns: (transfer full): a new #GstIterator.
485  *
486  * MT safe.
487  */
488 GstIterator *
489 gst_iterator_filter (GstIterator * it, GCompareFunc func, gpointer user_data)
491   GstIteratorFilter *result;
493   g_return_val_if_fail (it != NULL, NULL);
494   g_return_val_if_fail (func != NULL, NULL);
496   result = (GstIteratorFilter *) gst_iterator_new (sizeof (GstIteratorFilter),
497       it->type, it->lock, it->master_cookie,
498       (GstIteratorNextFunction) filter_next,
499       (GstIteratorItemFunction) NULL,
500       (GstIteratorResyncFunction) filter_resync,
501       (GstIteratorFreeFunction) filter_free);
502   it->lock = NULL;
503   result->func = func;
504   result->user_data = user_data;
505   result->slave = it;
507   return GST_ITERATOR (result);
510 /**
511  * gst_iterator_fold:
512  * @it: The #GstIterator to fold over
513  * @func: (scope call): the fold function
514  * @ret: the seed value passed to the fold function
515  * @user_data: (closure): user data passed to the fold function
516  *
517  * Folds @func over the elements of @iter. That is to say, @func will be called
518  * as @func (object, @ret, @user_data) for each object in @it. The normal use
519  * of this procedure is to accumulate the results of operating on the objects in
520  * @ret.  If object is a refcounted object its refcount will be increased 
521  * before @func is called, and it should be unrefed after use in @func.
522  *
523  * This procedure can be used (and is used internally) to implement the
524  * gst_iterator_foreach() and gst_iterator_find_custom() operations.
525  *
526  * The fold will proceed as long as @func returns TRUE. When the iterator has no
527  * more arguments, %GST_ITERATOR_DONE will be returned. If @func returns FALSE,
528  * the fold will stop, and %GST_ITERATOR_OK will be returned. Errors or resyncs
529  * will cause fold to return %GST_ITERATOR_ERROR or %GST_ITERATOR_RESYNC as
530  * appropriate.
531  *
532  * The iterator will not be freed.
533  *
534  * Returns: A #GstIteratorResult, as described above.
535  *
536  * MT safe.
537  */
538 GstIteratorResult
539 gst_iterator_fold (GstIterator * it, GstIteratorFoldFunction func,
540     GValue * ret, gpointer user_data)
542   gpointer item;
543   GstIteratorResult result;
545   while (1) {
546     result = gst_iterator_next (it, &item);
547     switch (result) {
548       case GST_ITERATOR_OK:
549         if (!func (item, ret, user_data))
550           goto fold_done;
551         else
552           break;
553       case GST_ITERATOR_RESYNC:
554       case GST_ITERATOR_ERROR:
555         goto fold_done;
556       case GST_ITERATOR_DONE:
557         goto fold_done;
558     }
559   }
561 fold_done:
562   return result;
565 typedef struct
567   GFunc func;
568   gpointer user_data;
569 } ForeachFoldData;
571 static gboolean
572 foreach_fold_func (gpointer item, GValue * unused, ForeachFoldData * data)
574   data->func (item, data->user_data);
575   return TRUE;
578 /**
579  * gst_iterator_foreach:
580  * @it: The #GstIterator to iterate
581  * @func: (scope call): the function to call for each element.
582  * @user_data: (closure): user data passed to the function
583  *
584  * Iterate over all element of @it and call the given function @func for
585  * each element.  As in gst_iterator_fold(), the refcount of a refcounted 
586  * object will be increased before @func is called, and should be unrefed
587  * after use.
588  *
589  * Returns: the result call to gst_iterator_fold(). The iterator will not be
590  * freed.
591  *
592  * MT safe.
593  */
594 GstIteratorResult
595 gst_iterator_foreach (GstIterator * it, GFunc func, gpointer user_data)
597   ForeachFoldData data;
599   data.func = func;
600   data.user_data = user_data;
602   return gst_iterator_fold (it, (GstIteratorFoldFunction) foreach_fold_func,
603       NULL, &data);
606 typedef struct
608   GCompareFunc func;
609   gpointer user_data;
610 } FindCustomFoldData;
612 static gboolean
613 find_custom_fold_func (gpointer item, GValue * ret, FindCustomFoldData * data)
615   if (data->func (item, data->user_data) == 0) {
616     g_value_set_pointer (ret, item);
617     return FALSE;
618   } else {
619     return TRUE;
620   }
623 /* FIXME 0.11:
624  * We should store ref/unref (or copy/free) functions for the type
625  * in GstIterator. The unref but only if it's not a match behaviour
626  * of find_custom() is very bad for bindings. The ref/unref functions
627  * are also useful for the fold and filter cases.
628  */
630 /**
631  * gst_iterator_find_custom:
632  * @it: The #GstIterator to iterate
633  * @func: (scope call): the compare function to use
634  * @user_data: (closure): user data passed to the compare function
635  *
636  * Find the first element in @it that matches the compare function @func.
637  * @func should return 0 when the element is found.  As in gst_iterator_fold(),
638  * the refcount of a refcounted object will be increased before @func is 
639  * called, and should be unrefed after use in @func unless it is the matching
640  * element.
641  *
642  * The iterator will not be freed.
643  *
644  * This function will return NULL if an error happened to the iterator.
645  *
646  * Returns: (transfer full): The element in the iterator that matches the compare
647  * function or NULL when no element matched.
648  *
649  * MT safe.
650  */
651 gpointer
652 gst_iterator_find_custom (GstIterator * it, GCompareFunc func,
653     gpointer user_data)
655   GValue ret = { 0, };
656   GstIteratorResult res;
657   FindCustomFoldData data;
659   g_value_init (&ret, G_TYPE_POINTER);
660   data.func = func;
661   data.user_data = user_data;
663   do {
664     res =
665         gst_iterator_fold (it, (GstIteratorFoldFunction) find_custom_fold_func,
666         &ret, &data);
667     if (res == GST_ITERATOR_RESYNC)
668       gst_iterator_resync (it);
669   } while (res == GST_ITERATOR_RESYNC);
671   /* no need to unset, it's just a pointer */
672   return g_value_get_pointer (&ret);
675 typedef struct
677   GstIterator parent;
678   gpointer object;
679   GstCopyFunction copy;
680   GFreeFunc free;
681   gboolean visited;
682 } GstSingleObjectIterator;
684 static guint32 _single_object_dummy_cookie = 0;
686 static GstIteratorResult
687 gst_single_object_iterator_iterator_next (GstSingleObjectIterator * it,
688     gpointer * result)
690   if (it->visited || !it->object) {
691     *result = NULL;
692     return GST_ITERATOR_DONE;
693   }
695   *result = it->copy (it->object);
696   it->visited = TRUE;
697   return GST_ITERATOR_OK;
700 static void
701 gst_single_object_iterator_resync (GstSingleObjectIterator * it)
703   it->visited = FALSE;
706 static void
707 gst_single_object_iterator_free (GstSingleObjectIterator * it)
709   if (it->object)
710     it->free (it->object);
711   g_free (it);
714 /**
715  * gst_iterator_new_single:
716  * @type: #GType of the passed object
717  * @object: object that this iterator should return
718  * @copy: Function that returns a copy of @object or increases its refcount
719  * @free: Function to be called for freeing @object
720  *
721  * This #GstIterator is a convenient iterator for the common
722  * case where a #GstIterator needs to be returned but only
723  * a single object has to be considered. This happens often
724  * for the #GstPadIterIntLinkFunction.
725  *
726  * Returns: the new #GstIterator for @object.
727  *
728  * Since: 0.10.25
729  */
730 GstIterator *
731 gst_iterator_new_single (GType type, gpointer object, GstCopyFunction copy,
732     GFreeFunc free)
734   GstSingleObjectIterator *result;
736   g_return_val_if_fail (copy != NULL, NULL);
737   g_return_val_if_fail (free != NULL, NULL);
739   result = (GstSingleObjectIterator *)
740       gst_iterator_new (sizeof (GstSingleObjectIterator),
741       type, NULL, &_single_object_dummy_cookie,
742       (GstIteratorNextFunction) gst_single_object_iterator_iterator_next, NULL,
743       (GstIteratorResyncFunction) gst_single_object_iterator_resync,
744       (GstIteratorFreeFunction) gst_single_object_iterator_free);
746   result->object = (object) ? copy (object) : NULL;
747   result->copy = copy;
748   result->free = free;
749   result->visited = FALSE;
751   return (GstIterator *) result;