xref: /php-src/ext/spl/tests/dualiterator.inc (revision 75a678a7)
1<?php
2
3/** @file dualiterator.inc
4 * @ingroup Examples
5 * @brief class DualIterator
6 * @author  Marcus Boerger
7 * @date    2003 - 2006
8 *
9 * SPL - Standard PHP Library
10 */
11
12/** @ingroup Examples
13 * @brief   Synchronous iteration over two iterators
14 * @author  Marcus Boerger
15 * @version 1.3
16 */
17class DualIterator implements Iterator
18{
19    const CURRENT_LHS   = 0x01;
20    const CURRENT_RHS   = 0x02;
21    const CURRENT_ARRAY = 0x03;
22    const CURRENT_0     = 0x00;
23
24    const KEY_LHS   = 0x10;
25    const KEY_RHS   = 0x20;
26    const KEY_0     = 0x00;
27
28    const DEFAULT_FLAGS = 0x13;
29
30    private $lhs;
31    private $rhs;
32    private $flags;
33
34    /** construct iterator from two iterators
35     *
36     * @param lhs   Left  Hand Side Iterator
37     * @param rhs   Right Hand Side Iterator
38     * @param flags iteration flags
39     */
40    function __construct(Iterator $lhs, Iterator $rhs,
41                    $flags = 0x13 /*DualIterator::DEFAULT_FLAGS*/)
42    {
43        $this->lhs   = $lhs;
44        $this->rhs   = $rhs;
45        $this->flags = $flags;
46    }
47
48    /** @return Left Hand Side Iterator
49     */
50    function getLHS()
51    {
52        return $this->lhs;
53    }
54
55    /** @return Right Hand Side Iterator
56     */
57    function getRHS()
58    {
59        return $this->rhs;
60    }
61
62    /** @param flags new flags
63     */
64    function setFlags($flags)
65    {
66        $this->flags = $flags;
67    }
68
69    /** @return current flags
70     */
71    function getFlags()
72    {
73        return $this->flags;
74    }
75
76    /** rewind both inner iterators
77     */
78    function rewind(): void
79    {
80        $this->lhs->rewind();
81        $this->rhs->rewind();
82    }
83
84    /** @return whether both inner iterators are valid
85     */
86    function valid(): bool
87    {
88        return $this->lhs->valid() && $this->rhs->valid();
89    }
90
91    /** @return current value depending on CURRENT_* flags
92     */
93    function current(): mixed
94    {
95        switch($this->flags & 0x0F)
96        {
97        default:
98        case self::CURRENT_ARRAY:
99            return array($this->lhs->current(), $this->rhs->current());
100        case self::CURRENT_LHS:
101            return $this->lhs->current();
102        case self::CURRENT_RHS:
103            return $this->rhs->current();
104        case self::CURRENT_0:
105            return NULL;
106        }
107    }
108
109    /** @return key value depending on KEY_* flags
110     */
111    function key(): mixed
112    {
113        switch($this->flags & 0xF0)
114        {
115        default:
116        case self::KEY_LHS:
117            return $this->lhs->key();
118        case self::KEY_RHS:
119            return $this->rhs->key();
120        case self::KEY_0:
121            return NULL;
122        }
123    }
124
125    /** move both inner iterators forward
126     */
127    function next(): void
128    {
129        $this->lhs->next();
130        $this->rhs->next();
131    }
132
133    /** @return whether both inner iterators are valid and have identical
134     * current and key values or both are non valid.
135     */
136    function areIdentical()
137    {
138        return $this->valid()
139             ? $this->lhs->current() === $this->rhs->current()
140            && $this->lhs->key()     === $this->rhs->key()
141             : $this->lhs->valid()   ==  $this->rhs->valid();
142    }
143
144    /** @return whether both inner iterators are valid and have equal current
145     * and key values or both are non valid.
146     */
147    function areEqual()
148    {
149        return $this->valid()
150             ? $this->lhs->current() ==  $this->rhs->current()
151            && $this->lhs->key()     ==  $this->rhs->key()
152             : $this->lhs->valid()   ==  $this->rhs->valid();
153    }
154
155    /** Compare two iterators
156     *
157     * @param lhs   Left  Hand Side Iterator
158     * @param rhs   Right Hand Side Iterator
159     * @param identical whether to use areEqual() or areIdentical()
160     * @return whether both iterators are equal/identical
161     *
162     * @note If one implements RecursiveIterator the other must do as well.
163     *       And if both do then a recursive comparison is being used.
164     */
165    static function compareIterators(Iterator $lhs, Iterator $rhs,
166                                     $identical = false)
167    {
168        if ($lhs instanceof RecursiveIterator)
169        {
170            if ($rhs instanceof RecursiveIterator)
171            {
172                $it = new RecursiveDualIterator($lhs, $rhs,
173                                self::CURRENT_0 | self::KEY_0);
174                $it = new RecursiveCompareDualIterator($it);
175            }
176            else
177            {
178                return false;
179            }
180        }
181        else
182        {
183            $it = new DualIterator($lhs, $rhs, self::CURRENT_0 | self::KEY_0);
184        }
185
186        if ($identical)
187        {
188            foreach($it as $n)
189            {
190                if (!$it->areIdentical())
191                {
192                    return false;
193                }
194            }
195        }
196        else
197        {
198            foreach($it as $n)
199            {
200                if (!$it->areEqual())
201                {
202                    return false;
203                }
204            }
205        }
206        return $identical ? $it->areIdentical() : $it->areEqual();
207    }
208}
209
210?>
211