/* * Copyright (C) 2005 by the gtk2-perl team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: GstIterator.xs,v 1.3 2006/12/02 16:37:31 kaffeetisch Exp $ */ #include "gst2perl.h" /* ------------------------------------------------------------------------- */ SV * newSVGstIterator (const GstIterator *iter) { AV *av, *dummy; SV *tie, *ref; HV *stash; av = newAV (); dummy = newAV (); ref = newRV_noinc ((SV *) av); stash = gv_stashpv ("GStreamer::Iterator", TRUE); sv_bless (ref, stash); tie = newRV_noinc ((SV *) dummy); stash = gv_stashpv ("GStreamer::Iterator::Tie", TRUE); sv_bless (tie, stash); /* Both the dummy and the real array need to have the path stored in * the ext slot. SvGstIterator looks for it in the real array. * FETCHSIZE and FETCH look for it in the dummy. */ sv_magic ((SV *) dummy, 0, PERL_MAGIC_ext, (const char *) iter, 0); sv_magic ((SV *) av, 0, PERL_MAGIC_ext, (const char *) iter, 0); sv_magic ((SV *) av, tie, PERL_MAGIC_tied, Nullch, 0); return ref; } GstIterator * SvGstIterator (SV *sv) { MAGIC *mg; if (!sv || !SvROK (sv) || !(mg = mg_find (SvRV (sv), PERL_MAGIC_ext))) return NULL; return (GstIterator *) mg->mg_ptr; } /* ------------------------------------------------------------------------- */ SV * sv_from_pointer (gpointer pointer, GType gtype, gboolean own) { GType fundamental = G_TYPE_FUNDAMENTAL (gtype); switch (fundamental) { case G_TYPE_INTERFACE: case G_TYPE_OBJECT: return gperl_new_object (G_OBJECT (pointer), own); case G_TYPE_BOXED: /* special case for SVs, which are stored directly * rather than inside blessed wrappers. */ if (gtype == GPERL_TYPE_SV) { SV * sv = pointer; return sv ? g_boxed_copy (GPERL_TYPE_SV, pointer) : &PL_sv_undef; } return gperl_new_boxed (pointer, gtype, own); case G_TYPE_PARAM: return newSVGParamSpec (pointer); case G_TYPE_POINTER: return newSViv (PTR2IV (pointer)); default: croak ("FIXME: unhandled type - %d (%s fundamental for %s)\n", fundamental, g_type_name (fundamental), g_type_name (gtype)); } } /* ------------------------------------------------------------------------- */ MODULE = GStreamer::Iterator PACKAGE = GStreamer::Iterator PREFIX = gst_iterator_ =for position SYNOPSIS =head1 SYNOPSIS foreach ($bin -> iterate_elements()) { do_something($_); } my $iter = $bin -> iterate_elements(); while ($_ = $iter -> next()) { do_something($_); } =cut =for position DESCRIPTION =head1 DESCRIPTION There are two ways to use a I. The first is to use normal Perl looping stuff: foreach ($bin -> iterate_elements()) { do_something($_); } This is very elegant and Perl-ish, but may also be a bit slower. The alternative is to use the I method: my $iter = $bin -> iterate_elements(); while ($_ = $iter -> next()) { do_something($_); } This is hardly beautiful but avoids looping over the elements unnecessarily and is thus faster. =cut void DESTROY (GstIterator *iter) CODE: gst_iterator_free (iter); # GstIteratorResult gst_iterator_next (GstIterator *it, gpointer *elem); SV * gst_iterator_next (iter) GstIterator *iter PREINIT: gboolean done = FALSE; gpointer item; CODE: while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: RETVAL = sv_from_pointer (item, iter->type, TRUE); done = TRUE; break; case GST_ITERATOR_RESYNC: gst_iterator_resync (iter); break; case GST_ITERATOR_DONE: RETVAL = &PL_sv_undef; done = TRUE; break; case GST_ITERATOR_ERROR: croak ("An error occured while iterating"); } } OUTPUT: RETVAL # FIXME: Needed? # void gst_iterator_push (GstIterator *it, GstIterator *other); # FIXME? # GstIterator * gst_iterator_filter (GstIterator *it, GCompareFunc func, gpointer user_data); # GstIteratorResult gst_iterator_fold (GstIterator *iter, GstIteratorFoldFunction func, GValue *ret, gpointer user_data); # GstIteratorResult gst_iterator_foreach (GstIterator *iter, GFunc func, gpointer user_data); # gpointer gst_iterator_find_custom (GstIterator *it, GCompareFunc func, gpointer user_data); MODULE = GStreamer::Iterator PACKAGE = GStreamer::Iterator::Tie IV FETCHSIZE (GstIterator *iter) PREINIT: gboolean done = FALSE; gpointer item; CODE: RETVAL = 0; gst_iterator_resync (iter); while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: RETVAL++; break; case GST_ITERATOR_RESYNC: RETVAL = 0; gst_iterator_resync (iter); break; /* FIXME: Is it ok to handle ERROR like this? */ case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; break; } } OUTPUT: RETVAL SV * FETCH (GstIterator *iter, IV index) PREINIT: gboolean done = FALSE; gpointer item; IV counter = -1; CODE: RETVAL = &PL_sv_undef; gst_iterator_resync (iter); while (!done) { switch (gst_iterator_next (iter, &item)) { case GST_ITERATOR_OK: counter++; break; case GST_ITERATOR_RESYNC: counter = -1; gst_iterator_resync (iter); break; /* FIXME: Is it ok to handle ERROR like this? */ case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: done = TRUE; break; } if (counter == index) { RETVAL = sv_from_pointer (item, iter->type, TRUE); done = TRUE; } } OUTPUT: RETVAL