Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Zend Framework (http://framework.zend.com/)
|
Chris@0
|
4 *
|
Chris@0
|
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
|
Chris@0
|
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
Chris@0
|
7 * @license http://framework.zend.com/license/new-bsd New BSD License
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 namespace Zend\Stdlib;
|
Chris@0
|
11
|
Chris@0
|
12 use Countable;
|
Chris@0
|
13 use Iterator;
|
Chris@0
|
14
|
Chris@0
|
15 class PriorityList implements Iterator, Countable
|
Chris@0
|
16 {
|
Chris@0
|
17 const EXTR_DATA = 0x00000001;
|
Chris@0
|
18 const EXTR_PRIORITY = 0x00000002;
|
Chris@0
|
19 const EXTR_BOTH = 0x00000003;
|
Chris@0
|
20 /**
|
Chris@0
|
21 * Internal list of all items.
|
Chris@0
|
22 *
|
Chris@0
|
23 * @var array[]
|
Chris@0
|
24 */
|
Chris@0
|
25 protected $items = [];
|
Chris@0
|
26
|
Chris@0
|
27 /**
|
Chris@0
|
28 * Serial assigned to items to preserve LIFO.
|
Chris@0
|
29 *
|
Chris@0
|
30 * @var int
|
Chris@0
|
31 */
|
Chris@0
|
32 protected $serial = 0;
|
Chris@0
|
33
|
Chris@0
|
34 /**
|
Chris@0
|
35 * Serial order mode
|
Chris@0
|
36 * @var integer
|
Chris@0
|
37 */
|
Chris@0
|
38 protected $isLIFO = 1;
|
Chris@0
|
39
|
Chris@0
|
40 /**
|
Chris@0
|
41 * Internal counter to avoid usage of count().
|
Chris@0
|
42 *
|
Chris@0
|
43 * @var int
|
Chris@0
|
44 */
|
Chris@0
|
45 protected $count = 0;
|
Chris@0
|
46
|
Chris@0
|
47 /**
|
Chris@0
|
48 * Whether the list was already sorted.
|
Chris@0
|
49 *
|
Chris@0
|
50 * @var bool
|
Chris@0
|
51 */
|
Chris@0
|
52 protected $sorted = false;
|
Chris@0
|
53
|
Chris@0
|
54 /**
|
Chris@0
|
55 * Insert a new item.
|
Chris@0
|
56 *
|
Chris@0
|
57 * @param string $name
|
Chris@0
|
58 * @param mixed $value
|
Chris@0
|
59 * @param int $priority
|
Chris@0
|
60 *
|
Chris@0
|
61 * @return void
|
Chris@0
|
62 */
|
Chris@0
|
63 public function insert($name, $value, $priority = 0)
|
Chris@0
|
64 {
|
Chris@12
|
65 if (! isset($this->items[$name])) {
|
Chris@0
|
66 $this->count++;
|
Chris@0
|
67 }
|
Chris@0
|
68
|
Chris@0
|
69 $this->sorted = false;
|
Chris@0
|
70
|
Chris@0
|
71 $this->items[$name] = [
|
Chris@0
|
72 'data' => $value,
|
Chris@0
|
73 'priority' => (int) $priority,
|
Chris@0
|
74 'serial' => $this->serial++,
|
Chris@0
|
75 ];
|
Chris@0
|
76 }
|
Chris@0
|
77
|
Chris@0
|
78 /**
|
Chris@0
|
79 * @param string $name
|
Chris@0
|
80 * @param int $priority
|
Chris@0
|
81 *
|
Chris@0
|
82 * @return $this
|
Chris@0
|
83 *
|
Chris@0
|
84 * @throws \Exception
|
Chris@0
|
85 */
|
Chris@0
|
86 public function setPriority($name, $priority)
|
Chris@0
|
87 {
|
Chris@12
|
88 if (! isset($this->items[$name])) {
|
Chris@0
|
89 throw new \Exception("item $name not found");
|
Chris@0
|
90 }
|
Chris@0
|
91
|
Chris@0
|
92 $this->items[$name]['priority'] = (int) $priority;
|
Chris@0
|
93 $this->sorted = false;
|
Chris@0
|
94
|
Chris@0
|
95 return $this;
|
Chris@0
|
96 }
|
Chris@0
|
97
|
Chris@0
|
98 /**
|
Chris@0
|
99 * Remove a item.
|
Chris@0
|
100 *
|
Chris@0
|
101 * @param string $name
|
Chris@0
|
102 * @return void
|
Chris@0
|
103 */
|
Chris@0
|
104 public function remove($name)
|
Chris@0
|
105 {
|
Chris@0
|
106 if (isset($this->items[$name])) {
|
Chris@0
|
107 $this->count--;
|
Chris@0
|
108 }
|
Chris@0
|
109
|
Chris@0
|
110 unset($this->items[$name]);
|
Chris@0
|
111 }
|
Chris@0
|
112
|
Chris@0
|
113 /**
|
Chris@0
|
114 * Remove all items.
|
Chris@0
|
115 *
|
Chris@0
|
116 * @return void
|
Chris@0
|
117 */
|
Chris@0
|
118 public function clear()
|
Chris@0
|
119 {
|
Chris@0
|
120 $this->items = [];
|
Chris@0
|
121 $this->serial = 0;
|
Chris@0
|
122 $this->count = 0;
|
Chris@0
|
123 $this->sorted = false;
|
Chris@0
|
124 }
|
Chris@0
|
125
|
Chris@0
|
126 /**
|
Chris@0
|
127 * Get a item.
|
Chris@0
|
128 *
|
Chris@0
|
129 * @param string $name
|
Chris@0
|
130 * @return mixed
|
Chris@0
|
131 */
|
Chris@0
|
132 public function get($name)
|
Chris@0
|
133 {
|
Chris@12
|
134 if (! isset($this->items[$name])) {
|
Chris@0
|
135 return;
|
Chris@0
|
136 }
|
Chris@0
|
137
|
Chris@0
|
138 return $this->items[$name]['data'];
|
Chris@0
|
139 }
|
Chris@0
|
140
|
Chris@0
|
141 /**
|
Chris@0
|
142 * Sort all items.
|
Chris@0
|
143 *
|
Chris@0
|
144 * @return void
|
Chris@0
|
145 */
|
Chris@0
|
146 protected function sort()
|
Chris@0
|
147 {
|
Chris@12
|
148 if (! $this->sorted) {
|
Chris@0
|
149 uasort($this->items, [$this, 'compare']);
|
Chris@0
|
150 $this->sorted = true;
|
Chris@0
|
151 }
|
Chris@0
|
152 }
|
Chris@0
|
153
|
Chris@0
|
154 /**
|
Chris@0
|
155 * Compare the priority of two items.
|
Chris@0
|
156 *
|
Chris@0
|
157 * @param array $item1,
|
Chris@0
|
158 * @param array $item2
|
Chris@0
|
159 * @return int
|
Chris@0
|
160 */
|
Chris@0
|
161 protected function compare(array $item1, array $item2)
|
Chris@0
|
162 {
|
Chris@0
|
163 return ($item1['priority'] === $item2['priority'])
|
Chris@12
|
164 ? ($item1['serial'] > $item2['serial'] ? -1 : 1) * $this->isLIFO
|
Chris@0
|
165 : ($item1['priority'] > $item2['priority'] ? -1 : 1);
|
Chris@0
|
166 }
|
Chris@0
|
167
|
Chris@0
|
168 /**
|
Chris@0
|
169 * Get/Set serial order mode
|
Chris@0
|
170 *
|
Chris@0
|
171 * @param bool|null $flag
|
Chris@0
|
172 *
|
Chris@0
|
173 * @return bool
|
Chris@0
|
174 */
|
Chris@0
|
175 public function isLIFO($flag = null)
|
Chris@0
|
176 {
|
Chris@0
|
177 if ($flag !== null) {
|
Chris@0
|
178 $isLifo = $flag === true ? 1 : -1;
|
Chris@0
|
179
|
Chris@0
|
180 if ($isLifo !== $this->isLIFO) {
|
Chris@0
|
181 $this->isLIFO = $isLifo;
|
Chris@0
|
182 $this->sorted = false;
|
Chris@0
|
183 }
|
Chris@0
|
184 }
|
Chris@0
|
185
|
Chris@0
|
186 return 1 === $this->isLIFO;
|
Chris@0
|
187 }
|
Chris@0
|
188
|
Chris@0
|
189 /**
|
Chris@0
|
190 * {@inheritDoc}
|
Chris@0
|
191 */
|
Chris@0
|
192 public function rewind()
|
Chris@0
|
193 {
|
Chris@0
|
194 $this->sort();
|
Chris@0
|
195 reset($this->items);
|
Chris@0
|
196 }
|
Chris@0
|
197
|
Chris@0
|
198 /**
|
Chris@0
|
199 * {@inheritDoc}
|
Chris@0
|
200 */
|
Chris@0
|
201 public function current()
|
Chris@0
|
202 {
|
Chris@0
|
203 $this->sorted || $this->sort();
|
Chris@0
|
204 $node = current($this->items);
|
Chris@0
|
205
|
Chris@0
|
206 return $node ? $node['data'] : false;
|
Chris@0
|
207 }
|
Chris@0
|
208
|
Chris@0
|
209 /**
|
Chris@0
|
210 * {@inheritDoc}
|
Chris@0
|
211 */
|
Chris@0
|
212 public function key()
|
Chris@0
|
213 {
|
Chris@0
|
214 $this->sorted || $this->sort();
|
Chris@0
|
215 return key($this->items);
|
Chris@0
|
216 }
|
Chris@0
|
217
|
Chris@0
|
218 /**
|
Chris@0
|
219 * {@inheritDoc}
|
Chris@0
|
220 */
|
Chris@0
|
221 public function next()
|
Chris@0
|
222 {
|
Chris@0
|
223 $node = next($this->items);
|
Chris@0
|
224
|
Chris@0
|
225 return $node ? $node['data'] : false;
|
Chris@0
|
226 }
|
Chris@0
|
227
|
Chris@0
|
228 /**
|
Chris@0
|
229 * {@inheritDoc}
|
Chris@0
|
230 */
|
Chris@0
|
231 public function valid()
|
Chris@0
|
232 {
|
Chris@0
|
233 return current($this->items) !== false;
|
Chris@0
|
234 }
|
Chris@0
|
235
|
Chris@0
|
236 /**
|
Chris@0
|
237 * @return self
|
Chris@0
|
238 */
|
Chris@0
|
239 public function getIterator()
|
Chris@0
|
240 {
|
Chris@0
|
241 return clone $this;
|
Chris@0
|
242 }
|
Chris@0
|
243
|
Chris@0
|
244 /**
|
Chris@0
|
245 * {@inheritDoc}
|
Chris@0
|
246 */
|
Chris@0
|
247 public function count()
|
Chris@0
|
248 {
|
Chris@0
|
249 return $this->count;
|
Chris@0
|
250 }
|
Chris@0
|
251
|
Chris@0
|
252 /**
|
Chris@0
|
253 * Return list as array
|
Chris@0
|
254 *
|
Chris@0
|
255 * @param int $flag
|
Chris@0
|
256 *
|
Chris@0
|
257 * @return array
|
Chris@0
|
258 */
|
Chris@0
|
259 public function toArray($flag = self::EXTR_DATA)
|
Chris@0
|
260 {
|
Chris@0
|
261 $this->sort();
|
Chris@0
|
262
|
Chris@0
|
263 if ($flag == self::EXTR_BOTH) {
|
Chris@0
|
264 return $this->items;
|
Chris@0
|
265 }
|
Chris@0
|
266
|
Chris@0
|
267 return array_map(
|
Chris@0
|
268 function ($item) use ($flag) {
|
Chris@0
|
269 return ($flag == PriorityList::EXTR_PRIORITY) ? $item['priority'] : $item['data'];
|
Chris@0
|
270 },
|
Chris@0
|
271 $this->items
|
Chris@0
|
272 );
|
Chris@0
|
273 }
|
Chris@0
|
274 }
|