/
BufferedIterator.php
154 lines (134 loc) · 3 KB
/
BufferedIterator.php
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
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.0.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Collection\Iterator;
use Cake\Collection\Collection;
use SplDoublyLinkedList;
/**
* Creates an iterator from another iterator that will keep in memory the results
* from the inner iterator so they don't have to be calculated again.
*/
class BufferedIterator extends Collection {
/**
* The in-memory cache containing results from previous iterators
*
* @var callable
*/
protected $_buffer;
/**
* Points to the next record number that should be fetched
*
* @var int
*/
protected $_index = 0;
/**
* Last record fetched from the inner iterator
*
* @var mixed
*/
protected $_current;
/**
* Last key obtained from the inner iterator
*
* @var mixed
*/
protected $_key;
/**
* Whether or not the internal iterator's rewind method was already
* called
*
* @var boolean
*/
protected $_started = false;
/**
* Whether or not the internal iterator's has reached its end
*
* @var boolean
*/
protected $_finished = false;
/**
* Maintains an in-memory cache of the results yielded by the internal
* iterator.
*
* @param array|\Traversable $items The items to be filtered.
*/
public function __construct($items) {
$this->_buffer = new SplDoublyLinkedList;
parent::__construct($items);
}
/**
* Returns the current key in the iterator
*
* @return mixed
*/
public function key() {
return $this->_key;
}
/**
* Returns the current record in the iterator
*
* @return mixed
*/
public function current() {
return $this->_current;
}
/**
* Rewinds the collection
*
* @return void
*/
public function rewind() {
if ($this->_index === 0 && !$this->_started) {
$this->_started = true;
parent::rewind();
return;
}
$this->_index = 0;
}
/**
* Returns whether or not the iterator has more elements
*
* @return boolean
*/
public function valid() {
if ($this->_buffer->offsetExists($this->_index)) {
$current = $this->_buffer->offsetGet($this->_index);
$this->_current = $current['value'];
$this->_key = $current['key'];
return true;
}
$valid = parent::valid();
if ($valid) {
$this->_current = parent::current();
$this->_key = parent::key();
$this->_buffer->push([
'key' => $this->_key,
'value' => $this->_current
]);
}
$this->_finished = !$valid;
return $valid;
}
/**
* Advances the iterator pointer to the next element
*
* @return void
*/
public function next() {
$this->_index++;
if (!$this->_finished) {
parent::next();
}
}
}