<?php
/**
* An iterator that acts as a window to its inner-iterator. It does this by
* providing deque-like functionality (allowing shifting off the front and
* popping off of the end.)
*
* This class has similar functionality to PHP's LimitIterator.
*
* @author Peter Goodman
*/
class WindowingIterator extends IteratorIterator implements Countable, SeekableIterator {
protected $_key,
$_offset,
$_limit,
$_it;
/**
* WindowingIterator(SeekableIterator)
*/
public function __construct(SeekableIterator $it) {
assert($it instanceof Countable);
$this->_limit = count($it);
$this->_key = $this->_offset = 0;
$this->_it = $it;
}
/**
* $i->current(void) -> mixed
*
* Return the current row.
*/
public function current() {
return $this->_it->current();
}
/**
* $i->shift(void) -> mixed
*
* Shift off and return the first record from the record iterator. If there
* is no record to shift off this will return NULL.
*/
public function shift() {
$this->rewind();
if(!$this->valid())
return NULL;
$ret = $this->current();
$this->_offset++;
if($this->_key - $this->_offset <= 0)
$this->_key++;
return $ret;
}
/**
* $i->pop(void) -> mixed
*
* Pop off and return the last record from the record iterator. If there
* are no records left then this will return NULL.
*/
public function pop() {
try {
$this->seek($this->_limit - 1);
$ret = $this->current();
$this->_limit--;
$this->rewind();
return $ret;
} catch(OutOfBoundsException $e) {
return NULL;
}
}
/**
* $i->seek(int $key) -> void
*
* Seek to a specific row in the iterator. Rows are indexed from [0, n-1].
* If the row number supplied is out of bounds, ie: it is below zero or
* above n-1 then a OutOfBoundsException is thrown.
*/
public function seek($key) {
// make sure the key is in the right place
if($key < $this->_offset || $key >= $this->_limit) {
throw new OutOfBoundsException(
"Could not access row [{$key}] of record set."
);
}
$this->_key = $key;
}
/**
* $i->key(void) -> int
*
* Return the current row number.
*/
public function key() {
return $this->_key;
}
/**
* $i->count(void) -> int
*
* Return the number of rows viewable through the window.
*/
public function count() {
return $this->_limit;
}
/**
* $i->rewind(void) -> void
*
* Rewind the record iterator to start at row zero.
*/
public function rewind() {
if($this->_key > $this->_offset)
$this->seek($this->_offset);
}
/**
* $i->valid(void) -> bool
*
* Check if the row in the record iterator represented by the current row
* id exists. If it doesn't this will return FALSE.
*/
public function valid() {
return ($this->_key < $this->_limit) &&
($this->_key >= $this->_offset);
}
/**
* $i->next(void) -> void
*
* Move the internal record pointer to the next record.
*/
public function next() {
$this->_key++;
}
}