X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=classes%2Fpliteratorutils.php;h=875aac70cd4707747e4d1a3c5f71d61d69db66fc;hb=7299bfcef8ccaffa52ecd0ca3adf92c84f79c248;hp=9390efe70940ee2a24ad4d0fe7afdcd380efb577;hpb=851962db3851d0ff89cf6cfaa9dcb82487e437bf;p=platal.git diff --git a/classes/pliteratorutils.php b/classes/pliteratorutils.php index 9390efe..875aac7 100644 --- a/classes/pliteratorutils.php +++ b/classes/pliteratorutils.php @@ -21,6 +21,13 @@ 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. @@ -86,7 +93,8 @@ class PlIteratorUtils } /** Build an iterator whose values are iterators too; such a 'subIterator' will end - * when the value of $callback changes + * when the value of $callback changes; + * WARNING: will fast-forward the current subiterator until it is over ! * @param iterator The source iterator * @param callback The callback for detecting changes. XXX: Might be called twice on a given object * @return an iterator @@ -127,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. @@ -424,6 +464,8 @@ class PlSubIterator implements PlIterator private $source; private $callback; private $next = null; // The next item, if it has been fetched too early by a subiterator + private $pos = 0; + private $sub = null; public function __construct(PlIterator $source, $callback) { @@ -431,12 +473,26 @@ class PlSubIterator implements PlIterator $this->callback = $callback; } + /** WARNING: this will "fast-forward" the subiterator to its end + */ public function next() { if ($this->last()) { return null; } else { - return new PlInnerSubIterator($this->source, $this->callback, $this, $this->next); + if ($this->sub != null) { + while (!$this->sub->last()) { + $this->sub->next(); + } + } + + if ($this->last()) { + return null; + } + + ++$this->pos; + $this->sub = new PlInnerSubIterator($this->source, $this->callback, $this, $this->next); + return $this->sub; } } @@ -447,14 +503,20 @@ class PlSubIterator implements PlIterator return $this->source->total(); } + /** This will only return true if the current subiterator was the last one, + * and if it has been fully used + */ public function last() { + if ($this->sub != null && !$this->sub->last()) { + return false; + } return ($this->source->last() && $this->next == null); } public function first() { - return $this->source->first(); + return $this->pos == 1; } // Called by a subiterator to "rewind" the core iterator @@ -474,7 +536,8 @@ class PlInnerSubIterator implements PlIterator private $curval = null; private $curelt = null; - private $begin = true; + private $val = null; + private $pos = 0; private $stepped = false; private $over = false; @@ -484,6 +547,7 @@ class PlInnerSubIterator implements PlIterator $this->callback = $callback; $this->parent = $parent; $this->next = $next; + $this->parent->setNext(null); } public function value() @@ -503,12 +567,18 @@ class PlInnerSubIterator implements PlIterator $this->curelt = $this->next; $this->next = null; } else { + if ($this->source->last()) { + $this->over = true; + return; + } $this->curelt = $this->source->next(); } - if ($this->begin) { + if ($this->pos == 0) { + $this->val = call_user_func($this->callback, $this->curelt); + $this->curval = $this->val; + } else { $this->curval = call_user_func($this->callback, $this->curelt); - $this->begin = false; } $this->stepped = true; @@ -516,18 +586,24 @@ class PlInnerSubIterator implements PlIterator public function next() { + if ($this->over) { + return null; + } + $this->_step(); + + if ($this->over) { + return null; + } + + ++$this->pos; $this->stepped = false; - if ($this->curelt) { - $val = call_user_func($this->callback, $this->curelt); - if ($val == $this->curval) { - $this->curval = $val; - return $this->curelt; - } else { - $this->parent->setNext($this->curelt); - } + if ($this->val == $this->curval) { + return $this->curelt; } + + $this->parent->setNext($this->curelt); $this->over = true; return null; } @@ -541,12 +617,16 @@ class PlInnerSubIterator implements PlIterator public function last() { - return $this->over; + if ($this->over) { + return true; + } + $this->_step(); + return $this->over || ($this->val != $this->curval); } public function first() { - return false; + return $this->pos == 1; } } @@ -592,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(); @@ -604,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(); @@ -615,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; } @@ -626,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() @@ -644,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; } @@ -715,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: ?>