gnomemm r1679 - in gstreamermm/trunk: . gstreamer/src tests



Author: jaalburqu
Date: Mon Aug 11 04:37:08 2008
New Revision: 1679
URL: http://svn.gnome.org/viewvc/gnomemm?rev=1679&view=rev

Log:
2008-08-11  Josà Alburquerque  <jaalburqu svn gnome org>

	* gstreamer/src/iterator.ccg:
	* gstreamer/src/iterator.hg: Removed ConcurrentUpdateException and
	used std::runtime_error with description for iterator concurrent
	update.  Renamed is_last() to is_end() (logic was flawed on what
	Gst::ITERATOR_DONE means -- one past last element, not *on* last
	element).  Added Gst::IteratorBasic (for non reference counted
	objects) and made Gst::Iterator derive from it.  Added (questionable?)
	operator->() to Gst::Iterator.
	* tests/test-iterator.cc: Rewrote test.

Modified:
   gstreamermm/trunk/ChangeLog
   gstreamermm/trunk/gstreamer/src/iterator.ccg
   gstreamermm/trunk/gstreamer/src/iterator.hg
   gstreamermm/trunk/tests/test-iterator.cc

Modified: gstreamermm/trunk/gstreamer/src/iterator.ccg
==============================================================================
--- gstreamermm/trunk/gstreamer/src/iterator.ccg	(original)
+++ gstreamermm/trunk/gstreamer/src/iterator.ccg	Mon Aug 11 04:37:08 2008
@@ -20,17 +20,3 @@
  */
 
 #include <gst/gstenumtypes.h>
-
-namespace Gst
-{
-
-ConcurrentUpdateException::ConcurrentUpdateException()
-: std::runtime_error(what())
-{}
-
-const char* ConcurrentUpdateException::what() const throw()
-{
-  return "Concurrent update of iterator elements.  Please resync iterator.";
-}
-
-} //namespace Gst

Modified: gstreamermm/trunk/gstreamer/src/iterator.hg
==============================================================================
--- gstreamermm/trunk/gstreamer/src/iterator.hg	(original)
+++ gstreamermm/trunk/gstreamer/src/iterator.hg	Mon Aug 11 04:37:08 2008
@@ -30,21 +30,14 @@
 _WRAP_ENUM(IteratorItem, GstIteratorItem)
 _WRAP_ENUM(IteratorResult, GstIteratorResult)
 
-/** Exception thrown by Gst::IteratorBase<> increment operators when the
- * elements are updated after element processing is underway by the iterator.
- */
-class ConcurrentUpdateException : std::runtime_error
-{
-public:
-  ConcurrentUpdateException();
-  virtual const char* what() const throw();
-};
-
 /**  Gst::IteratorBase â Base class for classes that retrieve multiple elements
  * in a thread safe way.
  *
  * Classes derived from Gst::IteratorBase are used to retrieve multiple objects
- * from another object in a thread safe way.
+ * from another object in a thread safe way.  They are implemented as C++ like
+ * input iterators so they do not support multi-passing, but they are usable
+ * enough for iterating through a list of items and referencing them in a
+ * single pass.
  *
  * Various GStreamer objects provide access to their internal structures using
  * an iterator.
@@ -53,38 +46,34 @@
 class IteratorBase
 {
 public:
-  /** Frees the underlying C instance if a destroy value of true was used to
-   * wrap it.
-   */
-  virtual ~IteratorBase();
-
-  /** Move to the next iterator item.
+  /** Moves to the next iterator item.
    *
-   * @return The result of the iteration. Please note that a return of
-   * Gst::ITERATOR_DONE means that the iterator is on the last item.  MT safe. 
+   * @return The result of the iteration. MT safe. 
    */
-  IteratorResult next();
+  virtual IteratorResult next();
 
-  /** Resync the iterator. This function is mostly called after next() returns
-   * Gst::ITERATOR_RESYNC.  In essence, the iterator is reset to the first item
-   * because a concurrent update of the iterator's list of element occurred
-   * while element processing was underway which means a call to this method is
-   * necessary.
+  /** Resynchronize the iterator. This function is mostly called after next()
+   * returns Gst::ITERATOR_RESYNC.  A result of Gst::ITERATOR_RESYNC from
+   * next() means that a concurrent update was made to the iterator list during
+   * iteration and the iterator needs to be resynchronized before continuing.
+   * Use this function to resynchronize.
    */
   void resync();
 
-  /** Tells if iterator is at start of list (not on first item, but just
-   * before it).
+  /** Tells if the iterator is at the start of the list (not on the first item,
+   * but just before it).  Increment the iterator or use
+   * Gst::IteratorBasic::begin() to go to the first item.
    *
-   * @return true if iterator is at start of list, false otherwise.
+   * @return true if the iterator is at the start of the list, false otherwise.
    */
   bool is_start() const;
 
-  /** Tells if iterator is on the last element.
+  /** Tells if the iterator is at the end of the list (just after the last
+   * element).
    *
-   * @return true if iterator is at end of list, false otherwise.
+   * @return true if the iterator is at the end of the list, false otherwise.
    */
-  bool is_last() const;
+  bool is_end() const;
 
   /** Tells whether the iterator is valid and can be dereferenced.
    */
@@ -96,6 +85,11 @@
   ///Provides access to the underlying C GObject.
   const GstIterator*    cobj() const    { return cobject_; };
 
+  /** Frees the underlying C instance if a destroy value of true was used to
+   * wrap it.
+   */
+  virtual ~IteratorBase();
+
 protected:
   /// Default constructor.
   IteratorBase();
@@ -107,14 +101,14 @@
    */
   IteratorBase(const IteratorBase<CppType>&);
 
-  /** Construct an IteratorBase from an underlying C object.
+  /** Constructs an IteratorBase from an underlying C object.
    * @param castitem The underlying C object.
-   * @param destroy Whether to destroy underlying C object along with the
+   * @param destroy Whether to destroy the underlying C object along with the
    * wrapper.
    */
   IteratorBase(GstIterator* castitem, bool destroy=true);
 
-  /** Assignment operator.  It replaces the contents of this iterator with the
+  /** Assignment operator.  It replaces the contents of the iterator with the
    * contents of the new one freeing the underlying C object if a destroy value
    * of true was used when wrapping it.  Please note that copying and assigning
    * merely shares the underlying C object.  Operations on the copy are also
@@ -138,17 +132,74 @@
   void swap(IteratorBase<CppType>& other);
 };
 
-/**  Gst::Iterator â Class that retrieve multiple elements in a thread safe way.
+/**  Gst::IteratorBasic â Class that retrieves multiple elements in a thread
+ * safe way.
+ * Gst::IteratorBasic iterates specifically through elements that are not
+ * reference counted.  Though it is mostly not used, it is included for
+ * completeness.  Gst::Iterator, which iterates through reference counted
+ * objects is mostly used for iterating through objects because the ones that
+ * are iterated in GStreamer are mostly reference counted.
+ */
+template <class CppType>
+class IteratorBasic : public IteratorBase<CppType>
+{
+public:
+  ///Default constructor.
+  IteratorBasic();
+
+  /** Creates a Gst::IteratorBasic wrapper for a GstIterator object.  The
+   * underlying @a castitem will be freed with the Gst::IteratorBasic
+   * destruction if a destroy value of true is given.
+   *
+   * @param castitem The C instance to wrap.
+   * @param destroy Whether to destroy the underlying C object with the
+   * wrapper.
+   */
+  IteratorBasic(GstIterator* castitem, bool destroy=true);
+
+  /** Resynchronizes the iterator and moves the iterator to the first item.
+   *
+   * @throw std::runtime_error (if a Gst::ITERATOR_ERROR is encountered or if a
+   * concurrent update to the iterator occurs while it is advanced to the first
+   * element).
+   */
+  void begin();
+
+  /** Dereferences the iterator and obtains the underlying object.
+   */
+  CppType operator*() const;
+
+  /** Prefix auto-increment operator.  It advances to the next item in the
+   * iterator.  It is faster than the postfix operator.
+   * @throw std::runtime_error (if a Gst::ITERATOR_ERROR is encountered or if a
+   * concurrent update to the iterator occurs while it iterates).
+   */
+  IteratorBasic<CppType>& operator++();
+
+  /** Postfix auto-increment operator.  It advances to the next item in the
+   * iterator.
+   * @throw std::runtime_error (if a Gst::ITERATOR_ERROR is encountered or if a
+   * concurrent update to the iterator occurs while it iterates).
+   */
+  IteratorBasic<CppType> operator++(int);
+};
+
+/**  Gst::Iterator â Class that retrieve multiple reference counted elements in
+ * a thread safe way.
  * Gst::Iterator iterates specifically through elements that are reference
  * counted and therefore dereferencing the elements of the iterator yields a
  * Glib::RefPtr<> to the C++ element type.
  */
 template <class CppType>
-class Iterator : public IteratorBase<CppType>
+class Iterator : public IteratorBasic<CppType>
 {
 public:
+  ///Default constructor.
+  Iterator();
+
   /** Creates a Gst::Iterator wrapper for a GstIterator object.  The underlying
-   * @a castitem will be freed with the Gst::Iterator destruction.
+   * @a castitem will be freed with the Gst::Iterator destruction if a destroy
+   * value of true is given.
    *
    * @param castitem The C instance to wrap.
    * @param destroy Whether to destroy the underlying C object with the
@@ -156,21 +207,32 @@
    */
   Iterator(GstIterator* castitem, bool destroy=true);
 
-  /** Dereference this iterator and obtain the underlying Glib::RefPtr<>.
+  /** Moves to the next iterator item.
+   *
+   * @return The result of the iteration. MT safe. 
+   */
+  IteratorResult next();
+
+  /** Dereferences the iterator and obtains the underlying Glib::RefPtr<>.
    */
   Glib::RefPtr<CppType> operator*() const;
 
+  //TODO: Should this operator be included?
+  /** Accesses underlying object member through the RefPtr<>.
+   */
+  CppType* operator->() const;
+
   /** Prefix auto-increment operator.  It advances to the next item in the
    * iterator.  It is faster than the postfix operator.
-   * @throw Gst::ConcurrentUpdateException.
-   * @throw std::runtime_error (when Gst::ITERATOR_ERROR is encountered).
+   * @throw std::runtime_error (if a Gst::ITERATOR_ERROR is encountered or if a
+   * concurrent update to the iterator occurs while it iterates).
    */
   Iterator<CppType>& operator++();
 
   /** Postfix auto-increment operator.  It advances to the next item in the
    * iterator.
-   * @throw Gst::ConcurrentUpdateException.
-   * @throw std::runtime_error (when Gst::ITERATOR_ERROR is encountered).
+   * @throw std::runtime_error (if a Gst::ITERATOR_ERROR is encountered or if a
+   * concurrent update to the iterator occurs while it iterates).
    */
   Iterator<CppType> operator++(int);
 };
@@ -183,6 +245,11 @@
 IteratorResult IteratorBase<CppType>::next()
 {
   current_result = (Gst::IteratorResult) gst_iterator_next(cobj(), &current);
+
+  // Set current to NULL if iterator is done:
+  if (current_result == Gst::ITERATOR_DONE)
+    current = 0;
+
   return current_result;
 }
 
@@ -201,9 +268,9 @@
 }
 
 template<class CppType>
-bool IteratorBase<CppType>::is_last() const
+bool IteratorBase<CppType>::is_end() const
 {
-  return (current != 0 && current_result == Gst::ITERATOR_DONE);
+  return (current_result == Gst::ITERATOR_DONE);
 }
 
 template<class CppType>
@@ -274,34 +341,116 @@
   }
 }
 
-/******************* Gst::Iterator<CppType> **************************/
+/***************** Gst::IteratorBasic<CppType> ***********************/
 
 template <class CppType>
-Iterator<CppType>::Iterator(GstIterator* castitem, bool destroy)
+IteratorBasic<CppType>::IteratorBasic()
+  : IteratorBase<CppType>()
+{}
+
+template <class CppType>
+IteratorBasic<CppType>::IteratorBasic(GstIterator* castitem, bool destroy)
   : IteratorBase<CppType>(castitem, destroy)
 {}
 
+template<class CppType>
+void IteratorBasic<CppType>::begin()
+{
+  this->resync();
+  ++(*this);
+}
+
 template <class CppType>
-Glib::RefPtr<CppType> Iterator<CppType>::operator*() const
+CppType IteratorBasic<CppType>::operator*() const
 {
   typedef typename CppType::BaseObjectType CType;
 
   if (this->current)
     return Glib::wrap((CType*)(this->current));
   else
-    return Glib::RefPtr<CppType>(0);
+    return CppType();
 }
 
 template<class CppType>
-Iterator<CppType>& Iterator<CppType>::operator++()
+IteratorBasic<CppType>& IteratorBasic<CppType>::operator++()
 {
   const IteratorResult result = this->next();
 
   if (result == Gst::ITERATOR_RESYNC)
-    throw ConcurrentUpdateException();
+    throw std::runtime_error("Concurrent update of iterator elements.  Please resync.");
   else if (result == Gst::ITERATOR_ERROR)
-    throw std::runtime_error("Iterator increment error.");
+    throw std::runtime_error("Iterator error while incrementing.");
+
+  return *this;
+}
+
+template<class CppType>
+IteratorBasic<CppType> IteratorBasic<CppType>::operator++(int)
+{
+  IteratorBasic<CppType> original = *this;
+  ++(*this);
+  return original;
+}
+
+/******************* Gst::Iterator<CppType> **************************/
+
+template <class CppType>
+Iterator<CppType>::Iterator()
+  : IteratorBasic<CppType>()
+{}
+
+template <class CppType>
+Iterator<CppType>::Iterator(GstIterator* castitem, bool destroy)
+  : IteratorBasic<CppType>(castitem, destroy)
+{}
+
+template <class CppType>
+IteratorResult Iterator<CppType>::next()
+{
+  const IteratorResult result = IteratorBasic<CppType>::next();
 
+  // Remove extra reference that gst_iterator_next() takes because references
+  // are taken when using Gst::Iterator<CppType> dereferencing operators (* and
+  // ->).
+  if (this->current)
+    g_object_unref(this->current);
+
+  return result;
+}
+
+template <class CppType>
+Glib::RefPtr<CppType> Iterator<CppType>::operator*() const
+{
+  typedef typename CppType::BaseObjectType CType;
+
+  if (this->current)
+  {
+    //Take extra reference when dereferencing.  The reference will disappear
+    //when Glib::RefPtr<> is destroyed.
+    return Glib::wrap((CType*)(this->current), true);
+  }
+  else
+    return Glib::RefPtr<CppType>(0);
+}
+
+template <class CppType>
+CppType* Iterator<CppType>::operator->() const
+{
+  typedef typename CppType::BaseObjectType CType;
+
+  if (this->current)
+  {
+    //Take extra reference when dereferencing.  The reference will disappear
+    //when Glib::RefPtr<> is destroyed.
+    return Glib::wrap((CType*)(this->current), true).operator->();
+  }
+  else
+    return (CppType*) 0;
+}
+template<class CppType>
+Iterator<CppType>& Iterator<CppType>::operator++()
+{
+  IteratorBasic<CppType>::operator++();
   return *this;
 }
 

Modified: gstreamermm/trunk/tests/test-iterator.cc
==============================================================================
--- gstreamermm/trunk/tests/test-iterator.cc	(original)
+++ gstreamermm/trunk/tests/test-iterator.cc	Mon Aug 11 04:37:08 2008
@@ -28,44 +28,53 @@
 
   Glib::RefPtr<Gst::Pipeline> pipeline;
   Glib::RefPtr<Gst::Bin> bin;
-  Glib::RefPtr<Gst::Element> source, sink;
+  Glib::RefPtr<Gst::Element> e1, e2, e3, e4;
 
   pipeline = Gst::Pipeline::create("my-pipeline");
   bin = Gst::Bin::create("my-bin");
 
-  source = Gst::ElementFactory::create_element("fakesrc", "source");
-  sink = Gst::ElementFactory::create_element("fakesink", "sink");
+  e1 = Gst::ElementFactory::create_element("fakesrc", "element1");
+  e2 = Gst::ElementFactory::create_element("fakesrc", "element2");
+  e3 = Gst::ElementFactory::create_element("fakesrc", "element3");
+  e4 = Gst::ElementFactory::create_element("fakesink", "element4");
 
-  bin->add(source)->add(sink);
+  bin->add(e1)->add(e2)->add(e3)->add(e4);
 
   pipeline->add(bin);
-  source->link(sink);
 
   std::cout << "The following elements have been added to bin '" <<
     bin->get_name() << "'." << std::endl;
 
   int iterations = 0;
   Gst::Iterator<Gst::Element> elements = bin->iterate_elements();
+  Gst::Iterator<Gst::Element> firstIter;
 
   try
   {
-    for ( ; !elements.is_last(); ++elements)
+    for (elements.begin(); !elements.is_end(); ++elements, ++iterations)
     {
-      if (elements)
-        std::cout << (*elements)->get_name() << std::endl;
+      if (!firstIter)
+        firstIter = elements;
 
-      iterations++;
+      std::cout << elements->get_name() << std::endl;
     }
-    ++elements;
+
+    if (firstIter)
+      std::cout << "The first element iterator processed is '" << 
+        firstIter->get_name() << "'." << std::endl;
+
+    if (elements)
+      std::cout << "elements.is_end() == true && (elements) is valid." <<
+        std::endl;
   }
   catch (std::runtime_error& e)
   {
     std::cout << "Runtime error while iterating through \"" <<
-      bin->get_name() << "'s\" elements." << std::endl;
+      bin->get_name() << "'s\" elements:" << std::endl << e.what() << std::endl;
   }
 
-  std::cout << "The loop iterated " << iterations << " to print bin '" <<
-  bin->get_name() << "' elements." << std::endl;
+  std::cout << "The loop iterated " << iterations <<
+    " time(s) to print bin '" << bin->get_name() << "' elements." << std::endl;
 
   return 0;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]