Add an extension hook for error reporting.
[platal.git] / classes / pliteratorutils.php
index 230dc5a..33dbfab 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /***************************************************************************
- *  Copyright (C) 2003-2010 Polytechnique.org                              *
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
  *  http://opensource.polytechnique.org/                                   *
  *                                                                         *
  *  This program is free software; you can redistribute it and/or modify   *
 
 class PlIteratorUtils
 {
+    /** Builds a new empty iterator
+     */
+    public static function emptyIterator()
+    {
+        return new PlEmptyIterator();
+    }
+
     /** Build an iterator over an array.
      * @param array The array.
      * @param depth The depth of iteration.
@@ -128,6 +135,38 @@ class PlIteratorUtils
         $callback = new _GetObjectPropertyCallback($property);
         return array($callback, 'get');
     }
+
+    /** Returns a wrapper around the PlIterator suitable for foreach() iterations
+     */
+    public static function foreachIterator(PlIterator $iterator)
+    {
+        return new SPLIterator($iterator);
+    }
+}
+
+/** Empty iterator
+ */
+class PlEmptyIterator implements PlIterator
+{
+    public function first()
+    {
+        return false;
+    }
+
+    public function last()
+    {
+        return false;
+    }
+
+    public function next()
+    {
+        return null;
+    }
+
+    public function total()
+    {
+        return 0;
+    }
 }
 
 /** Iterates over an array.
@@ -633,7 +672,8 @@ class PlParallelIterator implements PlIterator
     private $master_id;
     private $master;
 
-    private $stepped;
+    private $over = array();
+    private $stepped = array();
     private $current_elts = array();
     private $callback_res = array();
 
@@ -645,7 +685,8 @@ class PlParallelIterator implements PlIterator
 
         $this->ids = array_keys($iterators);
 
-        if (is_array($callbacks)) {
+        $v = array_values($callbacks);
+        if (is_array($v[0])) {
             $this->callbacks = $callbacks;
         } else {
             $this->callbacks = array();
@@ -656,6 +697,7 @@ class PlParallelIterator implements PlIterator
 
         foreach ($this->ids as $id) {
             $this->stepped[$id] = false;
+            $this->over[$id] = false;
             $this->current_elts[$id] = null;
             $this->callback_res[$id] = null;
         }
@@ -667,12 +709,24 @@ class PlParallelIterator implements PlIterator
             return;
         }
 
+        // Don't do anything if the iterator is at its end
+        if ($this->over[$id]) {
+            $this->stepped[$id] = true;
+            return;
+        }
+
         $it = $this->iterators[$id];
         $nxt = $it->next();
+        $this->stepped[$id] = true;
+        if ($nxt === null) {
+            $this->over[$id] = true;
+            $this->current_elts[$id] = null;
+            $this->callback_res[$id] = null;
+            return;
+        }
         $res = call_user_func($this->callbacks[$id], $nxt);
         $this->current_elts[$id] = $nxt;
         $this->callback_res[$id] = $res;
-        $this->stepped[$id] = true;
     }
 
     private function stepAll()
@@ -685,7 +739,7 @@ class PlParallelIterator implements PlIterator
     public function next()
     {
         $this->stepAll();
-        if ($this->current_elts[$this->master_id] == null) {
+        if ($this->current_elts[$this->master_id] === null) {
             return null;
         }
 
@@ -756,5 +810,48 @@ class _GetObjectPropertyCallback
     }
 }
 
+// Wrapper class to build a SPL iterator from a PlIterator
+class SPLIterator implements Iterator
+{
+    private $it;
+    private $pos;
+    private $value;
+
+    public function __construct(PlIterator $it)
+    {
+        $this->it = $it;
+        $this->pos = 0;
+        $this->value = $this->it->next();
+    }
+
+    public function rewind()
+    {
+        if ($this->pos != 0) {
+            throw new Exception("Rewind not supported on this iterator");
+        }
+    }
+
+    public function current()
+    {
+        return $this->value;
+    }
+
+    public function key()
+    {
+        return $this->pos;
+    }
+
+    public function next()
+    {
+        ++$this->pos;
+        $this->value = $this->it->next();
+    }
+
+    public function valid()
+    {
+        return !!$this->value;
+    }
+}
+
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
 ?>