summaryrefslogtreecommitdiff
path: root/ext/spl/examples/dualiterator.inc
blob: 4cee203436c71a55d7c8e1a68d3da33eeafb03f2 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
<?php

/** @file dualiterator.inc
 * @ingroup Examples
 * @brief class DualIterator
 * @author  Marcus Boerger
 * @date    2003 - 2006
 *
 * SPL - Standard PHP Library
 */

/** @ingroup Examples
 * @brief   Synchronous iteration over two iterators
 * @author  Marcus Boerger
 * @version 1.3
 */
class DualIterator implements Iterator
{
	const CURRENT_LHS   = 0x01;
	const CURRENT_RHS   = 0x02;
	const CURRENT_ARRAY = 0x03;
	const CURRENT_0     = 0x00;

	const KEY_LHS   = 0x10;
	const KEY_RHS   = 0x20;
	const KEY_0     = 0x00;
	
	const DEFAULT_FLAGS = 0x13;
	
	private $lhs;
	private $rhs;
	private $flags;

	/** construct iterator from two iterators
	 *
	 * @param lhs   Left  Hand Side Iterator
	 * @param rhs   Right Hand Side Iterator
	 * @param flags iteration flags
	 */
	function __construct(Iterator $lhs, Iterator $rhs, 
					$flags = 0x13 /*DualIterator::DEFAULT_FLAGS*/)
	{
		$this->lhs   = $lhs;
		$this->rhs   = $rhs;
		$this->flags = $flags;
	}

	/** @return Left Hand Side Iterator
	 */
	function getLHS()
	{
		return $this->lhs;
	}

	/** @return Right Hand Side Iterator
	 */
	function getRHS()
	{
		return $this->rhs;
	}

	/** @param flags new flags
	 */
	function setFlags($flags)
	{
		$this->flags = $flags;
	}

	/** @return current flags
	 */
	function getFlags()
	{
		return $this->flags;
	}

	/** rewind both inner iterators
	 */	
	function rewind()
	{
		$this->lhs->rewind();
		$this->rhs->rewind();	
	}

	/** @return whether both inner iterators are valid
	 */	
	function valid()
	{
		return $this->lhs->valid() && $this->rhs->valid();	
	}

	/** @return current value depending on CURRENT_* flags
	 */	
	function current()
	{
		switch($this->flags & 0x0F)
		{
		default:
		case self::CURRENT_ARRAY:
			return array($this->lhs->current(), $this->rhs->current());
		case self::CURRENT_LHS:
			return $this->lhs->current();
		case self::CURRENT_RHS:
			return $this->rhs->current();
		case self::CURRENT_0:
			return NULL;
		}
	}

	/** @return key value depending on KEY_* flags
	 */	
	function key()
	{
		switch($this->flags & 0xF0)
		{
		default:
		case self::KEY_LHS:
			return $this->lhs->key();
		case self::KEY_RHS:
			return $this->rhs->key();
		case self::KEY_0:
			return NULL;
		}
	}

	/** move both inner iterators forward
	 */	
	function next()
	{
		$this->lhs->next();
		$this->rhs->next();
	}

	/** @return whether both inner iterators are valid and have identical 
	 * current and key values or both are non valid.
	 */
	function areIdentical()
	{
		return $this->valid()
		     ? $this->lhs->current() === $this->rhs->current()
			&& $this->lhs->key()     === $this->rhs->key()
			 : $this->lhs->valid()   ==  $this->rhs->valid();
	}

	/** @return whether both inner iterators are valid and have equal current 
	 * and key values or both are non valid.
	 */
	function areEqual()
	{
		return $this->valid()
		     ? $this->lhs->current() ==  $this->rhs->current()
			&& $this->lhs->key()     ==  $this->rhs->key()
			 : $this->lhs->valid()   ==  $this->rhs->valid();
	}

	/** Compare two iterators
	 *
	 * @param lhs   Left  Hand Side Iterator
	 * @param rhs   Right Hand Side Iterator
	 * @param identical whether to use areEqual() or areIdentical()
	 * @return whether both iterators are equal/identical
	 *
	 * @note If one implements RecursiveIterator the other must do as well.
	 *       And if both do then a recursive comparison is being used.
	 */
	static function compareIterators(Iterator $lhs, Iterator $rhs, 
	                                 $identical = false)
	{
		if ($lhs instanceof RecursiveIterator)
		{
			if ($rhs instanceof RecursiveIterator)
			{
				$it = new RecursiveDualIterator($lhs, $rhs, 
								self::CURRENT_0 | self::KEY_0);
				$it = new RecursiveCompareDualIterator($it);
			}
			else
			{
				return false;
			}
		}
		else
		{
			$it = new DualIterator($lhs, $rhs, self::CURRENT_0 | self::KEY_0);
		}

		if ($identical)
		{
			foreach($it as $n)
			{
				if (!$it->areIdentical())
				{
					return false;
				}
			}
		}
		else
		{
			foreach($it as $n)
			{
				if (!$it->areEqual())
				{
					return false;
				}
			}
		}
		return $identical ? $it->areIdentical() : $it->areEqual();
	}
}

?>