X-Git-Url: http://git.polytechnique.org/?a=blobdiff_plain;f=classes%2Fpliteratorutils.php;h=dfa8a36fabd91b016a67f27d0afd2cc1935e82be;hb=5d0c351e87013f73d7176d55814dc650f91a2939;hp=0d67ac5b03ce4b6da7c8cb273e4a707125405e87;hpb=e8ddc3f28701273de2b5c0f822146ab2a39dea91;p=platal.git diff --git a/classes/pliteratorutils.php b/classes/pliteratorutils.php index 0d67ac5..dfa8a36 100644 --- a/classes/pliteratorutils.php +++ b/classes/pliteratorutils.php @@ -1,6 +1,6 @@ $x[$key]'; + * @param $key the index to retrieve in arrays + * @return a callback + */ + public static function arrayValueCallback($key) + { + $callback = new _GetArrayValueCallback($key); + return array($callback, 'get'); + } + + /** Returns the callback for '$x -> $x->prop'; + * @param $property The property to retrieve + * @return a callback + */ + public static function objectPropertyCallback($property) + { + $callback = new _GetObjectPropertyCallback($property); + return array($callback, 'get'); + } +} + /** Iterates over an array. */ class PlArrayIterator implements PlIterator @@ -259,5 +314,268 @@ class PlMergeIterator implements PlIterator } } + +class PlFilterIterator implements PlIterator { + private $source; + private $callback; + private $element; + private $start; + + public function __construct(PlIterator $source, $callback) + { + $this->source = $source; + $this->callback = $callback; + $this->start = true; + $this->element = null; + } + + private function fetchNext() + { + do { + $current = $this->source->next(); + if (!$current) { + $this->element = null; + $this->start = false; + return; + } + $res = call_user_func($this->callback, $current); + if ($res) { + $this->element = $current; + return; + } + } while (true); + } + + public function next() + { + if ($this->element && $this->start) { + $this->start = false; + } + $elt = $this->element; + if ($elt) { + $this->fetchNext(); + } + return $elt; + } + + public function total() + { + /* This is an approximation since the correct total + * cannot be computed without fetching all the elements + */ + return $this->source->total(); + } + + public function first() + { + return $this->start; + } + + public function last() + { + return !$this->start && !$this->element; + } +} + + +class PlMapIterator implements PlIterator +{ + private $source; + private $callback; + + public function __construct(PlIterator $source, $callback) + { + $this->source = $source; + $this->callback = $callback; + } + + public function next() + { + $elt = $this->source->next(); + if ($elt) { + return call_user_func($this->callback, $elt); + } else { + return null; + } + } + + public function total() + { + return $this->source->total(); + } + + public function first() + { + return $this->source->first(); + } + + public function last() + { + return $this->source->last(); + } +} + +class PlSubIterator implements PlIterator +{ + private $source; + private $callback; + private $next = null; // The next item, if it has been fetched too early by a subiterator + + public function __construct(PlIterator $source, $callback) + { + $this->source = $source; + $this->callback = $callback; + } + + public function next() + { + if ($this->last()) { + return null; + } else { + return new PlInnerSubIterator($this->source, $this->callback, $this, $this->next); + } + } + + /** This will always be a too big number, but the actual result can't be easily computed + */ + public function total() + { + return $this->source->total(); + } + + public function last() + { + return ($this->source->last() && $this->next == null); + } + + public function first() + { + return $this->source->first(); + } + + // Called by a subiterator to "rewind" the core iterator + public function setNext($item) + { + $this->next = $item; + } +} + +class PlInnerSubIterator implements PlIterator +{ + private $source; + private $callback; + private $parent; + + private $next; // Not null if the source has to be "rewinded" + + private $curval = null; + private $curelt = null; + private $stepped = false; + private $over = false; + + public function __construct(PlIterator $source, $callback, PlSubIterator $parent, $next = null) + { + $this->source = $source; + $this->callback = $callback; + $this->parent = $parent; + $this->next = $next; + } + + public function value() + { + $this->_step(); + return $this->curval; + } + + // Move one step, if the current element has been used + private function _step() + { + if ($this->stepped) { + return; + } + + if ($this->next != null) { + $this->curelt = $this->next; + $this->next = null; + } else { + $elt = $this->source->next(); + } + $this->stepped = true; + } + + public function next() + { + $this->_step(); + $this->stepped = false; + + if ($this->elt) { + $val = call_user_func($this->callback, $this->elt); + if ($val == $this->curval) { + $this->curval = $val; + return $this->elt; + } else { + $this->parent->setNext($this->elt); + } + } + $this->over = true; + return null; + } + + /** This will always be a too big number, but the actual result can't be easily computed + */ + public function total() + { + return $this->source->total(); + } + + public function last() + { + return $this->over; + } + + public function first() + { + return false; + } + +} + +// Wrapper class for 'arrayValueCallback' (get field $key of the given array) +class _GetArrayValueCallback +{ + private $key; + + public function __construct($key) + { + $this->key = $key; + } + + public function get(array $arr) + { + if (array_key_exists($this->key, $arr)) { + return $arr[$this->key]; + } else { + return null; + } + } +} + +// Wrapper class for 'objectPropertyCallback' (get property ->$blah of the given object) +class _GetObjectPropertyCallback +{ + private $property; + + public function __construct($property) + { + $this->property = $property; + } + + public function get($obj) + { + $p = $this->property; + return @$obj->$p; + } +} + // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8: ?>