summaryrefslogtreecommitdiff
path: root/ext/spl/internal/limititerator.inc
blob: 930ba535fadacd518e0167dff9add9caadfc90bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<?php

/** @file limititerator.inc
 * @ingroup SPL
 * @brief class LimitIterator
 * @author  Marcus Boerger
 * @date    2003 - 2005
 *
 * SPL - Standard PHP Library
 */

/**
 * @brief   Limited Iteration over another Iterator
 * @author  Marcus Boerger
 * @version 1.1
 * @since PHP 5.0
 *
 * A class that starts iteration at a certain offset and only iterates over
 * a specified amount of elements.
 *
 * This class uses SeekableIterator::seek() if available and rewind() plus
 * a skip loop otehrwise.
 */
class LimitIterator implements OuterIterator
{
	private $it;
	private $offset;
	private $count;
	private $pos;

	/** Construct
	 *
	 * @param it     Iterator to limit
	 * @param offset Offset to first element
	 * @param count  Maximum number of elements to show or NULL for all
	 */
	function __construct(Iterator $it, $offset = 0, $count = -1)
	{
		if ($offset < 0) {
			throw new exception('Parameter offset must be > 0');
		}
		if ($count < 0 && $count != -1) {
			throw new exception('Parameter count must either be -1 or a value greater than or equal to 0');
		}
		$this->it     = $it;
		$this->offset = $offset;
		$this->count  = $count;
		$this->pos    = 0;
	}
	
	/** Seek to specified position
	 * @param position offset to seek to (relative to beginning not offset
	 *                 specified in constructor).
	 * @throw exception when position is invalid
	 */
	function seek($position) {
		if ($position < $this->offset) {
			throw new exception('Cannot seek to '.$position.' which is below offset '.$this->offset);
		}
		if ($position > $this->offset + $this->count && $this->count != -1) {
			throw new exception('Cannot seek to '.$position.' which is behind offset '.$this->offset.' plus count '.$this->count);
		}
		if ($this->it instanceof SeekableIterator) {
			$this->it->seek($position);
			$this->pos = $position;
		} else {
			while($this->pos < $position && $this->it->valid()) {
				$this->next();
			}
		}
	}

    /** Rewind to offset specified in constructor
     */
	function rewind()
	{
		$this->it->rewind();
		$this->pos = 0;
		$this->seek($this->offset);
	}
	
	/** @return whether iterator is valid
	 */
	function valid() {
		return ($this->count == -1 || $this->pos < $this->offset + $this->count)
			 && $this->it->valid();
	}
	
	/** @return current key
	 */
	function key() {
		return $this->it->key();
	}

	/** @return current element
	 */
	function current() {
		return $this->it->current();
	}

	/** Forward to nect element
	 */
	function next() {
		$this->it->next();
		$this->pos++;
	}

	/** @return current position relative to zero (not to offset specified in 
	 *          constructor).
	 */
	function getPosition() {
		return $this->pos;
	}

	/**
	 * @return The inner iterator
	 */	
	function getInnerIterator()
	{
		return $this->it;
	}

	/** Aggregate the inner iterator
	 *
	 * @param func    Name of method to invoke
	 * @param params  Array of parameters to pass to method
	 */
	function __call($func, $params)
	{
		return call_user_func_array(array($this->it, $func), $params);
	}
}

?>