docs: remove outdated and pointless 'Last reviewed' lines from docs
[platform/upstream/gstreamer.git] / gst / gstiterator.c
1 /* GStreamer
2  * Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
3  * Copyright (C) 2011 Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  *
5  * gstiterator.h: Base class for iterating datastructures.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:gstiterator
25  * @short_description: Object to retrieve multiple elements in a threadsafe
26  * way.
27  * @see_also: #GstElement, #GstBin
28  *
29  * A GstIterator is used to retrieve multiple objects from another object in
30  * a threadsafe way.
31  *
32  * Various GStreamer objects provide access to their internal structures using
33  * an iterator.
34  *
35  * In general, whenever calling a GstIterator function results in your code
36  * receiving a refcounted object, the refcount for that object will have been
37  * increased.  Your code is responsible for unreffing that object after use.
38  *
39  * The basic use pattern of an iterator is as follows:
40  * |[
41  *   GstIterator *it = _get_iterator(object);
42  *   done = FALSE;
43  *   while (!done) {
44  *     switch (gst_iterator_next (it, &amp;item)) {
45  *       case GST_ITERATOR_OK:
46  *         ... use/change item here...
47  *         g_value_reset (&amp;item);
48  *         break;
49  *       case GST_ITERATOR_RESYNC:
50  *         ...rollback changes to items...
51  *         gst_iterator_resync (it);
52  *         break;
53  *       case GST_ITERATOR_ERROR:
54  *         ...wrong parameters were given...
55  *         done = TRUE;
56  *         break;
57  *       case GST_ITERATOR_DONE:
58  *         done = TRUE;
59  *         break;
60  *     }
61  *   }
62  *   g_value_unset (&amp;item);
63  *   gst_iterator_free (it);
64  * ]|
65  */
66
67 #include "gst_private.h"
68 #include <gst/gstiterator.h>
69
70 /**
71  * gst_iterator_copy:
72  * @it: a #GstIterator
73  *
74  * Copy the iterator and its state.
75  *
76  * Returns: a new copy of @it.
77  */
78 GstIterator *
79 gst_iterator_copy (const GstIterator * it)
80 {
81   GstIterator *copy;
82
83   copy = g_slice_copy (it->size, it);
84   if (it->copy)
85     it->copy (it, copy);
86
87   return copy;
88 }
89
90 G_DEFINE_BOXED_TYPE (GstIterator, gst_iterator,
91     (GBoxedCopyFunc) gst_iterator_copy, (GBoxedFreeFunc) gst_iterator_free);
92
93 static void
94 gst_iterator_init (GstIterator * it,
95     guint size,
96     GType type,
97     GMutex * lock,
98     guint32 * master_cookie,
99     GstIteratorCopyFunction copy,
100     GstIteratorNextFunction next,
101     GstIteratorItemFunction item,
102     GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
103 {
104   it->size = size;
105   it->type = type;
106   it->lock = lock;
107   it->master_cookie = master_cookie;
108   it->cookie = *master_cookie;
109   it->copy = copy;
110   it->next = next;
111   it->item = item;
112   it->resync = resync;
113   it->free = free;
114   it->pushed = NULL;
115 }
116
117 /**
118  * gst_iterator_new: (skip)
119  * @size: the size of the iterator structure
120  * @type: #GType of children
121  * @lock: pointer to a #GMutex.
122  * @master_cookie: pointer to a guint32 that is changed when the items in the
123  *    iterator changed.
124  * @copy: copy function
125  * @next: function to get next item
126  * @item: function to call on each item retrieved
127  * @resync: function to resync the iterator
128  * @free: function to free the iterator
129  *
130  * Create a new iterator. This function is mainly used for objects
131  * implementing the next/resync/free function to iterate a data structure.
132  *
133  * For each item retrieved, the @item function is called with the lock
134  * held. The @free function is called when the iterator is freed.
135  *
136  * Returns: the new #GstIterator.
137  *
138  * MT safe.
139  */
140 GstIterator *
141 gst_iterator_new (guint size,
142     GType type,
143     GMutex * lock,
144     guint32 * master_cookie,
145     GstIteratorCopyFunction copy,
146     GstIteratorNextFunction next,
147     GstIteratorItemFunction item,
148     GstIteratorResyncFunction resync, GstIteratorFreeFunction free)
149 {
150   GstIterator *result;
151
152   g_return_val_if_fail (size >= sizeof (GstIterator), NULL);
153   g_return_val_if_fail (g_type_qname (type) != 0, NULL);
154   g_return_val_if_fail (master_cookie != NULL, NULL);
155   g_return_val_if_fail (next != NULL, NULL);
156   g_return_val_if_fail (resync != NULL, NULL);
157   g_return_val_if_fail (free != NULL, NULL);
158
159   result = g_slice_alloc0 (size);
160   gst_iterator_init (result, size, type, lock, master_cookie, copy, next, item,
161       resync, free);
162
163   return result;
164 }
165
166 /*
167  * list iterator
168  */
169 typedef struct _GstListIterator
170 {
171   GstIterator iterator;
172   GObject *owner;
173   GList **orig;
174   GList *list;                  /* pointer in list */
175
176   void (*set_value) (GValue * value, gpointer item);
177 } GstListIterator;
178
179 static void
180 gst_list_iterator_copy (const GstListIterator * it, GstListIterator * copy)
181 {
182   if (copy->owner)
183     g_object_ref (copy->owner);
184 }
185
186 static GstIteratorResult
187 gst_list_iterator_next (GstListIterator * it, GValue * elem)
188 {
189   gpointer data;
190
191   if (it->list == NULL)
192     return GST_ITERATOR_DONE;
193
194   data = it->list->data;
195   it->list = g_list_next (it->list);
196
197   it->set_value (elem, data);
198
199   return GST_ITERATOR_OK;
200 }
201
202 static void
203 gst_list_iterator_resync (GstListIterator * it)
204 {
205   it->list = *it->orig;
206 }
207
208 static void
209 gst_list_iterator_free (GstListIterator * it)
210 {
211   if (it->owner)
212     g_object_unref (it->owner);
213 }
214
215 /**
216  * gst_iterator_new_list: (skip)
217  * @type: #GType of elements
218  * @lock: pointer to a #GMutex protecting the list.
219  * @master_cookie: pointer to a guint32 that is incremented when the list
220  *     is changed.
221  * @list: pointer to the list
222  * @owner: object owning the list
223  * @item: function to call on each item retrieved
224  *
225  * Create a new iterator designed for iterating @list.
226  *
227  * The list you iterate is usually part of a data structure @owner and is
228  * protected with @lock. 
229  *
230  * The iterator will use @lock to retrieve the next item of the list and it
231  * will then call the @item function before releasing @lock again.
232  *
233  * When a concurrent update to the list is performed, usually by @owner while
234  * holding @lock, @master_cookie will be updated. The iterator implementation
235  * will notice the update of the cookie and will return %GST_ITERATOR_RESYNC to
236  * the user of the iterator in the next call to gst_iterator_next().
237  *
238  * Returns: the new #GstIterator for @list.
239  *
240  * MT safe.
241  */
242 GstIterator *
243 gst_iterator_new_list (GType type,
244     GMutex * lock, guint32 * master_cookie, GList ** list, GObject * owner,
245     GstIteratorItemFunction item)
246 {
247   GstListIterator *result;
248   gpointer set_value;
249
250   if (g_type_is_a (type, G_TYPE_OBJECT)) {
251     set_value = g_value_set_object;
252   } else if (g_type_is_a (type, G_TYPE_BOXED)) {
253     set_value = g_value_set_boxed;
254   } else if (g_type_is_a (type, G_TYPE_POINTER)) {
255     set_value = g_value_set_pointer;
256   } else if (g_type_is_a (type, G_TYPE_STRING)) {
257     set_value = g_value_set_string;
258   } else {
259     g_critical ("List iterators can only be created for lists containing "
260         "instances of GObject, boxed types, pointer types and strings");
261     return NULL;
262   }
263
264   /* no need to lock, nothing can change here */
265   result = (GstListIterator *) gst_iterator_new (sizeof (GstListIterator),
266       type,
267       lock,
268       master_cookie,
269       (GstIteratorCopyFunction) gst_list_iterator_copy,
270       (GstIteratorNextFunction) gst_list_iterator_next,
271       (GstIteratorItemFunction) item,
272       (GstIteratorResyncFunction) gst_list_iterator_resync,
273       (GstIteratorFreeFunction) gst_list_iterator_free);
274
275   result->owner = owner ? g_object_ref (owner) : NULL;
276   result->orig = list;
277   result->list = *list;
278   result->set_value = set_value;
279
280   return GST_ITERATOR (result);
281 }
282
283 static void
284 gst_iterator_pop (GstIterator * it)
285 {
286   if (it->pushed) {
287     gst_iterator_free (it->pushed);
288     it->pushed = NULL;
289   }
290 }
291
292 /**
293  * gst_iterator_next:
294  * @it: The #GstIterator to iterate
295  * @elem: (out caller-allocates): pointer to hold next element
296  *
297  * Get the next item from the iterator in @elem. 
298  *
299  * Only when this function returns %GST_ITERATOR_OK, @elem will contain a valid
300  * value. @elem must have been initialized to the type of the iterator or
301  * initialized to zeroes with g_value_unset(). The caller is responsible for
302  * unsetting or resetting @elem with g_value_unset() or g_value_reset()
303  * after usage.
304  *
305  * When this function returns %GST_ITERATOR_DONE, no more elements can be
306  * retrieved from @it.
307  *
308  * A return value of %GST_ITERATOR_RESYNC indicates that the element list was
309  * concurrently updated. The user of @it should call gst_iterator_resync() to
310  * get the newly updated list. 
311  *
312  * A return value of %GST_ITERATOR_ERROR indicates an unrecoverable fatal error.
313  *
314  * Returns: The result of the iteration. Unset @elem after usage.
315  *
316  * MT safe.
317  */
318 GstIteratorResult
319 gst_iterator_next (GstIterator * it, GValue * elem)
320 {
321   GstIteratorResult result;
322
323   g_return_val_if_fail (it != NULL, GST_ITERATOR_ERROR);
324   g_return_val_if_fail (elem != NULL, GST_ITERATOR_ERROR);
325   g_return_val_if_fail (G_VALUE_TYPE (elem) == G_TYPE_INVALID
326       || G_VALUE_HOLDS (elem, it->type), GST_ITERATOR_ERROR);
327
328   if (G_VALUE_TYPE (elem) == G_TYPE_INVALID)
329     g_value_init (elem, it->type);
330
331 restart:
332   if (it->pushed) {
333     result = gst_iterator_next (it->pushed, elem);
334     if (result == GST_ITERATOR_DONE) {
335       /* we are done with this iterator, pop it and
336        * fallthrough iterating the main iterator again. */
337       gst_iterator_pop (it);
338     } else {
339       return result;
340     }
341   }
342
343   if (G_LIKELY (it->lock))
344     g_mutex_lock (it->lock);
345
346   if (G_UNLIKELY (*it->master_cookie != it->cookie)) {
347     result = GST_ITERATOR_RESYNC;
348     goto done;
349   }
350
351   result = it->next (it, elem);
352   if (result == GST_ITERATOR_OK && it->item) {
353     GstIteratorItem itemres;
354
355     itemres = it->item (it, elem);
356     switch (itemres) {
357       case GST_ITERATOR_ITEM_SKIP:
358         if (G_LIKELY (it->lock))
359           g_mutex_unlock (it->lock);
360         g_value_reset (elem);
361         goto restart;
362       case GST_ITERATOR_ITEM_END:
363         result = GST_ITERATOR_DONE;
364         g_value_reset (elem);
365         break;
366       case GST_ITERATOR_ITEM_PASS:
367         break;
368     }
369   }
370
371 done:
372   if (G_LIKELY (it->lock))
373     g_mutex_unlock (it->lock);
374
375   return result;
376 }
377
378 /**
379  * gst_iterator_resync:
380  * @it: The #GstIterator to resync
381  *
382  * Resync the iterator. this function is mostly called
383  * after gst_iterator_next() returned %GST_ITERATOR_RESYNC.
384  *
385  * When an iterator was pushed on @it, it will automatically be popped again
386  * with this function.
387  *
388  * MT safe.
389  */
390 void
391 gst_iterator_resync (GstIterator * it)
392 {
393   g_return_if_fail (it != NULL);
394
395   gst_iterator_pop (it);
396
397   if (G_LIKELY (it->lock))
398     g_mutex_lock (it->lock);
399   it->resync (it);
400   it->cookie = *it->master_cookie;
401   if (G_LIKELY (it->lock))
402     g_mutex_unlock (it->lock);
403 }
404
405 /**
406  * gst_iterator_free:
407  * @it: The #GstIterator to free
408  *
409  * Free the iterator.
410  *
411  * MT safe.
412  */
413 void
414 gst_iterator_free (GstIterator * it)
415 {
416   g_return_if_fail (it != NULL);
417
418   gst_iterator_pop (it);
419
420   it->free (it);
421
422   g_slice_free1 (it->size, it);
423 }
424
425 /**
426  * gst_iterator_push:
427  * @it: The #GstIterator to use
428  * @other: The #GstIterator to push
429  *
430  * Pushes @other iterator onto @it. All calls performed on @it are
431  * forwarded to @other. If @other returns %GST_ITERATOR_DONE, it is
432  * popped again and calls are handled by @it again.
433  *
434  * This function is mainly used by objects implementing the iterator
435  * next function to recurse into substructures.
436  *
437  * When gst_iterator_resync() is called on @it, @other will automatically be
438  * popped.
439  *
440  * MT safe.
441  */
442 void
443 gst_iterator_push (GstIterator * it, GstIterator * other)
444 {
445   g_return_if_fail (it != NULL);
446   g_return_if_fail (other != NULL);
447
448   it->pushed = other;
449 }
450
451 typedef struct _GstIteratorFilter
452 {
453   GstIterator iterator;
454   GstIterator *slave;
455
456   GMutex *master_lock;
457   GCompareFunc func;
458   GValue user_data;
459   gboolean have_user_data;
460 } GstIteratorFilter;
461
462 static GstIteratorResult
463 filter_next (GstIteratorFilter * it, GValue * elem)
464 {
465   GstIteratorResult result = GST_ITERATOR_ERROR;
466   gboolean done = FALSE;
467   GValue item = { 0, };
468
469   while (G_LIKELY (!done)) {
470     result = gst_iterator_next (it->slave, &item);
471     switch (result) {
472       case GST_ITERATOR_OK:
473         if (G_LIKELY (it->master_lock))
474           g_mutex_unlock (it->master_lock);
475         if (it->func (&item, &it->user_data) == 0) {
476           g_value_copy (&item, elem);
477           done = TRUE;
478         }
479         g_value_reset (&item);
480         if (G_LIKELY (it->master_lock))
481           g_mutex_lock (it->master_lock);
482         break;
483       case GST_ITERATOR_RESYNC:
484       case GST_ITERATOR_DONE:
485         done = TRUE;
486         break;
487       default:
488         g_assert_not_reached ();
489         break;
490     }
491   }
492   g_value_unset (&item);
493   return result;
494 }
495
496 static void
497 filter_copy (const GstIteratorFilter * it, GstIteratorFilter * copy)
498 {
499   copy->slave = gst_iterator_copy (it->slave);
500   copy->master_lock = copy->slave->lock ? copy->slave->lock : it->master_lock;
501   copy->slave->lock = NULL;
502
503   if (it->have_user_data) {
504     memset (&copy->user_data, 0, sizeof (copy->user_data));
505     g_value_init (&copy->user_data, G_VALUE_TYPE (&it->user_data));
506     g_value_copy (&it->user_data, &copy->user_data);
507   }
508 }
509
510 static void
511 filter_resync (GstIteratorFilter * it)
512 {
513   gst_iterator_resync (it->slave);
514 }
515
516 static void
517 filter_free (GstIteratorFilter * it)
518 {
519   if (it->have_user_data)
520     g_value_unset (&it->user_data);
521   gst_iterator_free (it->slave);
522 }
523
524 /**
525  * gst_iterator_filter:
526  * @it: The #GstIterator to filter
527  * @func: (scope call): the compare function to select elements
528  * @user_data: (closure): user data passed to the compare function
529  *
530  * Create a new iterator from an existing iterator. The new iterator
531  * will only return those elements that match the given compare function @func.
532  * The first parameter that is passed to @func is the #GValue of the current
533  * iterator element and the second parameter is @user_data. @func should
534  * return 0 for elements that should be included in the filtered iterator.
535  *
536  * When this iterator is freed, @it will also be freed.
537  *
538  * Returns: (transfer full): a new #GstIterator.
539  *
540  * MT safe.
541  */
542 GstIterator *
543 gst_iterator_filter (GstIterator * it, GCompareFunc func,
544     const GValue * user_data)
545 {
546   GstIteratorFilter *result;
547
548   g_return_val_if_fail (it != NULL, NULL);
549   g_return_val_if_fail (func != NULL, NULL);
550
551   result = (GstIteratorFilter *) gst_iterator_new (sizeof (GstIteratorFilter),
552       it->type, it->lock, it->master_cookie,
553       (GstIteratorCopyFunction) filter_copy,
554       (GstIteratorNextFunction) filter_next,
555       (GstIteratorItemFunction) NULL,
556       (GstIteratorResyncFunction) filter_resync,
557       (GstIteratorFreeFunction) filter_free);
558
559   result->master_lock = it->lock;
560   it->lock = NULL;
561   result->func = func;
562   if (user_data) {
563     g_value_init (&result->user_data, G_VALUE_TYPE (user_data));
564     g_value_copy (user_data, &result->user_data);
565     result->have_user_data = TRUE;
566   } else {
567     result->have_user_data = FALSE;
568   }
569   result->slave = it;
570
571   return GST_ITERATOR (result);
572 }
573
574 /**
575  * gst_iterator_fold:
576  * @it: The #GstIterator to fold over
577  * @func: (scope call): the fold function
578  * @ret: the seed value passed to the fold function
579  * @user_data: (closure): user data passed to the fold function
580  *
581  * Folds @func over the elements of @iter. That is to say, @func will be called
582  * as @func (object, @ret, @user_data) for each object in @it. The normal use
583  * of this procedure is to accumulate the results of operating on the objects in
584  * @ret.
585  *
586  * This procedure can be used (and is used internally) to implement the
587  * gst_iterator_foreach() and gst_iterator_find_custom() operations.
588  *
589  * The fold will proceed as long as @func returns TRUE. When the iterator has no
590  * more arguments, %GST_ITERATOR_DONE will be returned. If @func returns FALSE,
591  * the fold will stop, and %GST_ITERATOR_OK will be returned. Errors or resyncs
592  * will cause fold to return %GST_ITERATOR_ERROR or %GST_ITERATOR_RESYNC as
593  * appropriate.
594  *
595  * The iterator will not be freed.
596  *
597  * Returns: A #GstIteratorResult, as described above.
598  *
599  * MT safe.
600  */
601 GstIteratorResult
602 gst_iterator_fold (GstIterator * it, GstIteratorFoldFunction func,
603     GValue * ret, gpointer user_data)
604 {
605   GValue item = { 0, };
606   GstIteratorResult result;
607
608   while (1) {
609     result = gst_iterator_next (it, &item);
610     switch (result) {
611       case GST_ITERATOR_OK:
612         if (!func (&item, ret, user_data))
613           goto fold_done;
614
615         g_value_reset (&item);
616         break;
617       case GST_ITERATOR_RESYNC:
618       case GST_ITERATOR_ERROR:
619         goto fold_done;
620       case GST_ITERATOR_DONE:
621         goto fold_done;
622     }
623   }
624
625 fold_done:
626   g_value_unset (&item);
627
628   return result;
629 }
630
631 typedef struct
632 {
633   GstIteratorForeachFunction func;
634   gpointer user_data;
635 } ForeachFoldData;
636
637 static gboolean
638 foreach_fold_func (const GValue * item, GValue * unused, ForeachFoldData * data)
639 {
640   data->func (item, data->user_data);
641   return TRUE;
642 }
643
644 /**
645  * gst_iterator_foreach:
646  * @it: The #GstIterator to iterate
647  * @func: (scope call): the function to call for each element.
648  * @user_data: (closure): user data passed to the function
649  *
650  * Iterate over all element of @it and call the given function @func for
651  * each element.
652  *
653  * Returns: the result call to gst_iterator_fold(). The iterator will not be
654  * freed.
655  *
656  * MT safe.
657  */
658 GstIteratorResult
659 gst_iterator_foreach (GstIterator * it, GstIteratorForeachFunction func,
660     gpointer user_data)
661 {
662   ForeachFoldData data;
663
664   data.func = func;
665   data.user_data = user_data;
666
667   return gst_iterator_fold (it, (GstIteratorFoldFunction) foreach_fold_func,
668       NULL, &data);
669 }
670
671 typedef struct
672 {
673   GCompareFunc func;
674   gpointer user_data;
675   gboolean found;
676 } FindCustomFoldData;
677
678 static gboolean
679 find_custom_fold_func (const GValue * item, GValue * ret,
680     FindCustomFoldData * data)
681 {
682   if (data->func (item, data->user_data) == 0) {
683     data->found = TRUE;
684     g_value_copy (item, ret);
685     return FALSE;
686   } else {
687     return TRUE;
688   }
689 }
690
691 /**
692  * gst_iterator_find_custom:
693  * @it: The #GstIterator to iterate
694  * @func: (scope call): the compare function to use
695  * @elem: (out): pointer to a #GValue where to store the result
696  * @user_data: (closure): user data passed to the compare function
697  *
698  * Find the first element in @it that matches the compare function @func.
699  * @func should return 0 when the element is found. The first parameter
700  * to @func will be the current element of the iterator and the
701  * second parameter will be @user_data.
702  * The result will be stored in @elem if a result is found.
703  *
704  * The iterator will not be freed.
705  *
706  * This function will return FALSE if an error happened to the iterator
707  * or if the element wasn't found.
708  *
709  * Returns: Returns TRUE if the element was found, else FALSE.
710  *
711  * MT safe.
712  */
713 gboolean
714 gst_iterator_find_custom (GstIterator * it, GCompareFunc func,
715     GValue * elem, gpointer user_data)
716 {
717   GstIteratorResult res;
718   FindCustomFoldData data;
719
720   g_return_val_if_fail (G_VALUE_TYPE (elem) == G_TYPE_INVALID
721       || G_VALUE_HOLDS (elem, it->type), GST_ITERATOR_ERROR);
722
723   if (G_VALUE_TYPE (elem) == G_TYPE_INVALID)
724     g_value_init (elem, it->type);
725
726   data.func = func;
727   data.user_data = user_data;
728   data.found = FALSE;
729
730   do {
731     res =
732         gst_iterator_fold (it, (GstIteratorFoldFunction) find_custom_fold_func,
733         elem, &data);
734     if (res == GST_ITERATOR_RESYNC)
735       gst_iterator_resync (it);
736   } while (res == GST_ITERATOR_RESYNC);
737
738   if (!data.found)
739     g_value_unset (elem);
740
741   return data.found;
742 }
743
744 typedef struct
745 {
746   GstIterator parent;
747   GValue object;
748   gboolean visited;
749   gboolean empty;
750 } GstSingleObjectIterator;
751
752 static guint32 _single_object_dummy_cookie = 0;
753
754 static void
755 gst_single_object_iterator_copy (const GstSingleObjectIterator * it,
756     GstSingleObjectIterator * copy)
757 {
758   if (!it->empty) {
759     memset (&copy->object, 0, sizeof (copy->object));
760     g_value_init (&copy->object, it->parent.type);
761     g_value_copy (&it->object, &copy->object);
762   }
763 }
764
765 static GstIteratorResult
766 gst_single_object_iterator_next (GstSingleObjectIterator * it, GValue * result)
767 {
768   if (it->visited || it->empty)
769     return GST_ITERATOR_DONE;
770
771   g_value_copy (&it->object, result);
772   it->visited = TRUE;
773
774   return GST_ITERATOR_OK;
775 }
776
777 static void
778 gst_single_object_iterator_resync (GstSingleObjectIterator * it)
779 {
780   it->visited = FALSE;
781 }
782
783 static void
784 gst_single_object_iterator_free (GstSingleObjectIterator * it)
785 {
786   if (!it->empty)
787     g_value_unset (&it->object);
788 }
789
790 /**
791  * gst_iterator_new_single:
792  * @type: #GType of the passed object
793  * @object: object that this iterator should return
794  *
795  * This #GstIterator is a convenient iterator for the common
796  * case where a #GstIterator needs to be returned but only
797  * a single object has to be considered. This happens often
798  * for the #GstPadIterIntLinkFunction.
799  *
800  * Returns: the new #GstIterator for @object.
801  */
802 GstIterator *
803 gst_iterator_new_single (GType type, const GValue * object)
804 {
805   GstSingleObjectIterator *result;
806
807   result = (GstSingleObjectIterator *)
808       gst_iterator_new (sizeof (GstSingleObjectIterator),
809       type, NULL, &_single_object_dummy_cookie,
810       (GstIteratorCopyFunction) gst_single_object_iterator_copy,
811       (GstIteratorNextFunction) gst_single_object_iterator_next,
812       (GstIteratorItemFunction) NULL,
813       (GstIteratorResyncFunction) gst_single_object_iterator_resync,
814       (GstIteratorFreeFunction) gst_single_object_iterator_free);
815
816   if (object) {
817     g_value_init (&result->object, type);
818     g_value_copy (object, &result->object);
819     result->empty = FALSE;
820   } else {
821     result->empty = TRUE;
822   }
823   result->visited = FALSE;
824
825   return GST_ITERATOR (result);
826 }