}
/** 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
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)
{
$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;
}
}
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
private $curval = null;
private $curelt = null;
- private $begin = true;
+ private $val = null;
+ private $pos = 0;
private $stepped = false;
private $over = false;
$this->callback = $callback;
$this->parent = $parent;
$this->next = $next;
+ $this->parent->setNext(null);
}
public function value()
$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;
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;
}
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;
}
}