Passed
Push — master ( 1e2338...e1e446 )
by Fabio
05:44
created

TPriorityList::insertAtIndexInPriority()   F

Complexity

Conditions 21
Paths 137

Size

Total Lines 59
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 21

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 21
eloc 42
nc 137
nop 4
dl 0
loc 59
rs 3.8583
c 2
b 0
f 0
ccs 20
cts 20
cp 1
crap 21

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * TPriorityList class
4
 *
5
 * @author Brad Anderson <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
8
 */
9
10
namespace Prado\Collections;
11
12
use Prado\Exceptions\TInvalidDataTypeException;
13
use Prado\Exceptions\TInvalidDataValueException;
14
use Prado\Exceptions\TInvalidOperationException;
15
use Prado\TPropertyValue;
16
17
/**
18
 * TPriorityList class
19
 *
20
 * TPriorityList implements a priority ordered list collection class.  It allows you to specify
21
 * any numeric for priorities down to a specific precision.  The lower the numeric, the high the priority of the item in the
22
 * list.  Thus -10 has a higher priority than -5, 0, 10 (the default), 18, 10005, etc.  Per {@link round}, precision may be negative and
23
 * thus rounding can go by 10, 100, 1000, etc, instead of just .1, .01, .001, etc. The default precision allows for 8 decimal
24
 * places. There is also a default priority of 10, if no different default priority is specified or no item specific priority is indicated.
25
 * If you replace TList with this class it will  work exactly the same with items inserted set to the default priority, until you start
26
 * using different priorities than the default priority.
27
 *
28
 * As you access the PHP array features of this class, it flattens and caches the results.  If at all possible, this
29
 * will keep the cache fresh even when manipulated.  If this is not possible the cache is cleared.
30
 * When an array of items are needed and the cache is outdated, the cache is recreated from the items and their priorities
31
 *
32
 * You can access, append, insert, remove an item by using
33
 * {@link itemAt}, {@link add}, {@link insertAt}, and {@link remove}.
34
 * To get the number of the items in the list, use {@link getCount}.
35
 * TPriorityList can also be used like a regular array as follows,
36
 * <code>
37
 * $list[]=$item;  // append with the default priority.  It may not be the last item if other items in the list are prioritized after the default priority
38
 * $list[$index]=$item; // $index must be between 0 and $list->Count-1.  This sets the element regardless of priority.  Priority stays the same.
39
 * $list[$index]=$item; // $index is $list->Count.  This appends the item to the end of the list with the same priority as the last item in the list.
40
 * unset($list[$index]); // remove the item at $index
41
 * if(isset($list[$index])) // if the list has an item at $index
42
 * foreach($list as $index=>$item) // traverse each item in the list in proper priority order and add/insert order
43
 * $n=count($list); // returns the number of items in the list
44
 * </code>
45
 *
46
 * To extend TPriorityList for doing your own operations with each addition or removal,
47
 * override {@link insertAtIndexInPriority()} and {@link removeAtIndexInPriority()} and then call the parent.
48
 *
49
 * @author Brad Anderson <[email protected]>
50
 * @since 3.2a
51
 */
52
class TPriorityList extends TList
53
{
54
	use TPriorityCollectionTrait;
55
56
	/**
57
	 * Constructor.
58
	 * Initializes the list with an array or an iterable object.
59
	 * @param null|array|\Iterator $data the initial data. Default is null, meaning no initial data.
60
	 * @param bool $readOnly whether the list is read-only
61
	 * @param numeric $defaultPriority the default priority of items without specified priorities.
0 ignored issues
show
Bug introduced by
The type Prado\Collections\numeric was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
62
	 * @param int $precision the precision of the numeric priorities
63
	 * @throws TInvalidDataTypeException If data is not null and is neither an array nor an iterator.
64
	 */
65
	public function __construct($data = null, $readOnly = false, $defaultPriority = 10, $precision = 8)
66
	{
67
		$this->setPrecision($precision);
68
		$this->setDefaultPriority($defaultPriority);
0 ignored issues
show
Bug introduced by
It seems like $defaultPriority can also be of type integer; however, parameter $value of Prado\Collections\TPrior...t::setDefaultPriority() does only seem to accept Prado\Collections\numeric, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

68
		$this->setDefaultPriority(/** @scrutinizer ignore-type */ $defaultPriority);
Loading history...
69
		parent::__construct($data, $readOnly);
70
	}
71
72
	/**
73
	 * This is required for TPriorityCollectionTrait to determine the style of combining
74
	 * arrays.
75
	 * @return bool This returns true for array_merge (list style).  false would be
76
	 *   array_replace (map style).
77
	 */
78
	private function getPriorityCombineStyle(): bool
0 ignored issues
show
Unused Code introduced by
The method getPriorityCombineStyle() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
79
	{
80
		return true;
81
	}
82
83
	/**
84
	 * Returns the item at the index of a flattened priority list.
85
	 * {@link offsetGet} calls this method.
86
	 * @param int $index the index of the item to get
87
	 * @throws TInvalidDataValueException Issued when the index is invalid
88
	 * @return mixed the element at the offset
89
	 */
90 90
	public function itemAt($index)
91
	{
92 90
		if ($index >= 0 && $index < $this->getCount()) {
93 90
			$this->flattenPriorities();
94 25
			return $this->_fd[$index];
95
		} else {
96 90
			throw new TInvalidDataValueException('list_index_invalid', $index);
97 90
		}
98 90
	}
99 90
100
	/**
101
	 * Returns the item at an index within a priority
102
	 * @param int $index the index into the list of items at priority
103
	 * @param null|numeric $priority the priority which to index.  no parameter or null
104
	 *   will result in the default priority
105
	 * @throws TInvalidDataValueException if the index is out of the range at the
106 3
	 *   priority or no items at the priority.
107
	 * @return mixed the element at the offset, false if no element is found at the offset
108 3
	 */
109
	public function itemAtIndexInPriority($index, $priority = null)
110
	{
111
		$priority = $this->ensurePriority($priority);
112
		if (isset($this->_d[$priority]) && 0 <= $index && $index < count($this->_d[$priority])) {
113
			return $this->_d[$priority][$index];
114
		} else {
115 133
			throw new TInvalidDataValueException('prioritylist_index_invalid', $index, count($this->_d[$priority] ?? []), $priority);
116
		}
117 133
	}
118
119
	/**
120
	 * Appends an item into the list at the end of the specified priority.  The position of the added item may
121
	 * not be at the end of the list.
122
	 * @param mixed $item item to add into the list at priority
123
	 * @param null|numeric $priority priority blank or null for the default priority
124
	 * @throws TInvalidOperationException if the map is read-only
125 2
	 * @return int the index within the flattened array
126
	 */
127 2
	public function add($item, $priority = null)
128 2
	{
129
		if ($this->getReadOnly()) {
130 2
			throw new TInvalidOperationException('list_readonly', $this::class);
131
		}
132 2
133
		return $this->insertAtIndexInPriority($item, null, $priority, true);
134
	}
135 2
136
	/**
137
	 * Inserts an item at an index.  It reads the priority of the item at index within the flattened list
138
	 * and then inserts the item at that priority-index.
139
	 * @param int $index the specified position in the flattened list.
140
	 * @param mixed $item new item to add
141 116
	 * @throws TInvalidDataValueException If the index specified exceeds the bound
142
	 * @throws TInvalidOperationException if the list is read-only
143 116
	 */
144
	public function insertAt($index, $item)
145
	{
146
		if ($this->getReadOnly()) {
147
			throw new TInvalidOperationException('list_readonly', $this::class);
148
		}
149
150 90
		if (($priority = $this->priorityAt($index, true)) !== false) {
151
			$this->insertAtIndexInPriority($item, $priority[1], $priority[0]);
152 90
		} else {
153 90
			throw new TInvalidDataValueException('list_index_invalid', $index);
154
		}
155
	}
156
157
	/**
158 1
	 * Inserts an item at the specified index within a priority.  Override and call this method to
159
	 * insert your own functionality.
160 1
	 * @param mixed $item item to add within the list.
161
	 * @param null|false|int $index index within the priority to add the item, defaults to null which appends the item at the priority
162
	 * @param null|numeric $priority priority of the item.  defaults to null, which sets it to the default priority
163
	 * @param bool $preserveCache preserveCache specifies if this is a special quick function or not. This defaults to false.
164
	 * @throws TInvalidDataValueException If the index specified exceeds the bound
165
	 * @throws TInvalidOperationException if the list is read-only
166
	 * @todo PRADO version 4.3 remove $index: false => null conversion. false should be invalid input data.
167 90
	 */
168
	public function insertAtIndexInPriority($item, $index = null, $priority = null, $preserveCache = false)
169 90
	{
170 90
		if ($this->getReadOnly()) {
171
			throw new TInvalidOperationException('list_readonly', $this::class);
172
		}
173
		if ($index === false) {
174
			$index = null; // conversion, remove for PRADO 4.3
175
		}
176
		$itemPriority = null;
177 2
		if (($isPriorityItem = ($item instanceof IPriorityItem)) && ($priority === null || !is_numeric($priority))) {
178
			$itemPriority = $priority = $item->getPriority();
179 2
		}
180
		$priority = $this->ensurePriority($priority);
181
		if (($item instanceof IPriorityCapture) && (!$isPriorityItem || $itemPriority !== $priority)) {
182
			$item->setPriority($priority);
0 ignored issues
show
Bug introduced by
$priority of type string is incompatible with the type Prado\Collections\numeric expected by parameter $value of Prado\Collections\IPriorityCapture::setPriority(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
			$item->setPriority(/** @scrutinizer ignore-type */ $priority);
Loading history...
183
		}
184
185
		if (isset($this->_d[$priority])) {
186 16
			if ($index === null) {
187
				$c = count($this->_d[$priority]);
188 16
				$this->_d[$priority][] = $item;
189 16
			} elseif (0 <= $index && $index <= count($this->_d[$priority])) {
190
				$c = $index;
191
				array_splice($this->_d[$priority], $index, 0, [$item]);
192
			} else {
193
				throw new TInvalidDataValueException('prioritylist_index_invalid', $index, count($this->_d[$priority] ?? []), $priority);
194
			}
195
		} elseif ($index === 0 || $index === null) {
196 121
			$c = 0;
197
			$this->_o = false;
198 121
			$this->_d[$priority] = [$item];
199 112
		} else {
200 112
			throw new TInvalidDataValueException('prioritylist_index_invalid', $index, 0, $priority);
201
		}
202 121
203
		if ($preserveCache) {
204
			if ($this->_fd !== null) {
205
				$this->sortPriorities();
206
				foreach ($this->_d as $prioritykey => $items) {
207
					if ($prioritykey >= $priority) {
208 93
						break;
209
					} else {
210 93
						$c += count($items);
211 68
					}
212
				}
213
				array_splice($this->_fd, $c, 0, [$item]);
214 59
			}
215 59
		} else {
216 59
			if ($this->_fd !== null && count($this->_d) == 1) {
217 56
				array_splice($this->_fd, $c, 0, [$item]);
218
			} else {
219 59
				$this->_fd = null;
220
				$c = null;
221
			}
222
		}
223
224
		$this->_c++;
225
226
		return $c;
227
	}
228
229
230 8
	/**
231
	 * Removes an item from the priority list.
232 8
	 * The list will search for the item.  The first matching item found will be removed from the list.
233 8
	 * @param mixed $item item the item to be removed.
234 8
	 * @param null|bool|float $priority priority of item to remove. without this parameter it defaults to false.
235
	 * A value of false means any priority. null will be filled in with the default priority.
236 2
	 * @throws TInvalidDataValueException If the item does not exist
237
	 * @return int index within the flattened list at which the item is being removed
238
	 */
239
	public function remove($item, $priority = false)
240
	{
241
		if ($this->getReadOnly()) {
242
			throw new TInvalidOperationException('list_readonly', $this::class);
243
		}
244
245 16
		if (($p = $this->priorityOf($item, true)) !== false) {
246
			if ($priority !== false) {
247 16
				$priority = $this->ensurePriority($priority);
248 1
				if ($p[0] != $priority) {
249
					throw new TInvalidDataValueException('list_item_inexistent');
250 16
				}
251
			}
252 16
			$this->removeAtIndexInPriority($p[1], $p[0]);
253
			return $p[2];
254
		} else {
255
			throw new TInvalidDataValueException('list_item_inexistent');
256
		}
257
	}
258
259
	/**
260
	 * Removes an item at the specified index in the flattened list.
261 1
	 * @param int $index index of the item to be removed.
262
	 * @throws TInvalidDataValueException If the index specified exceeds the bound
263 1
	 * @throws TInvalidOperationException if the list is read-only
264 1
	 * @return mixed the removed item.
265
	 */
266 1
	public function removeAt($index)
267
	{
268 1
		if ($this->getReadOnly()) {
269 1
			throw new TInvalidOperationException('list_readonly', $this::class);
270
		}
271
272
		if (($priority = $this->priorityAt($index, true)) !== false) {
273
			return $this->removeAtIndexInPriority($priority[1], $priority[0]);
274
		}
275
		throw new TInvalidDataValueException('list_index_invalid', $index);
276
	}
277
278
	/**
279
	 * Removes the item at a specific index within a priority.  Override
280
	 * and call this method to insert your own functionality.
281 116
	 * @param int $index index of item to remove within the priority.
282
	 * @param null|numeric $priority priority of the item to remove, defaults to null, or left blank, it is then set to the default priority
283 116
	 * @throws TInvalidDataValueException If the item does not exist
284 1
	 * @return mixed the removed item.
285
	 */
286
	public function removeAtIndexInPriority($index, $priority = null)
287 116
	{
288
		if ($this->getReadOnly()) {
289
			throw new TInvalidOperationException('list_readonly', $this::class);
290
		}
291
292
		$priority = $this->ensurePriority($priority);
293
		if (!isset($this->_d[$priority]) || $index < 0 || $index >= ($c = count($this->_d[$priority]))) {
294
			throw new TInvalidDataValueException('list_item_inexistent');
295
		}
296
297
		if ($index === $c - 1) {
298 3
			$value = array_pop($this->_d[$priority]);
299
		} else {
300 3
			$value = array_splice($this->_d[$priority], $index, 1);
301 1
			$value = $value[0];
302
		}
303
		if (!count($this->_d[$priority])) {
304 2
			unset($this->_d[$priority]);
305 2
		}
306
307
		$this->_c--;
308
		$this->_fd = null;
309 2
		return $value;
310
	}
311
312
	/**
313
	 * Removes all items in the priority list by calling removeAtIndexInPriority from the last item to the first.
314
	 */
315
	public function clear(): void
316
	{
317
		if ($this->getReadOnly()) {
318
			throw new TInvalidOperationException('list_readonly', $this::class);
319
		}
320
321 116
		foreach (array_keys($this->_d) as $priority) {
322
			for ($index = count($this->_d[$priority]) - 1; $index >= 0; $index--) {
323 116
				$this->removeAtIndexInPriority($index, $priority);
324 1
			}
325
		}
326
	}
327 116
328 116
	/**
329
	 * @param mixed $item item
330 116
	 * @return int the index of the item in the flattened list (0 based), -1 if not found.
331
	 */
332 116
	public function indexOf($item)
333 116
	{
334 116
		$this->flattenPriorities();
335 116
		if (($index = array_search($item, $this->_fd, true)) === false) {
0 ignored issues
show
Bug introduced by
It seems like $this->_fd can also be of type null; however, parameter $haystack of array_search() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

335
		if (($index = array_search($item, /** @scrutinizer ignore-type */ $this->_fd, true)) === false) {
Loading history...
336 89
			return -1;
337 89
		} else {
338
			return $index;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $index also could return the type string which is incompatible with the documented return type integer.
Loading history...
339 65
		}
340
	}
341
342
	/**
343 116
	 * Returns the priority of a particular item
344 89
	 * @param mixed $item the item to look for within the list
345 89
	 * @param bool $withindex this specifies if the full positional data of the item within the list is returned.
346 89
	 * 		This defaults to false, if no parameter is provided, so only provides the priority number of the item by default.
347 106
	 * @return array|false|numeric the priority of the item in the list, false if not found.
348 1
	 *   if $withindex is true, an array is returned of [0 => $priority, 1 => $priorityIndex, 2 => flattenedIndex,
349 1
	 * 'priority' => $priority, 'index' => $priorityIndex, 'absindex' => flattenedIndex]
350
	 */
351 106
	public function priorityOf($item, $withindex = false)
352 106
	{
353 106
		$this->sortPriorities();
354
355
		$absindex = 0;
356 116
		foreach (array_keys($this->_d) as $priority) {
357 116
			if (($index = array_search($item, $this->_d[$priority], true)) !== false) {
358
				$absindex += $index;
359
				return $withindex ? [$priority, $index, $absindex,
360 20
						'priority' => $priority, 'index' => $index, 'absindex' => $absindex, ] : $priority;
361 20
			} else {
362 2
				$absindex += count($this->_d[$priority]);
363 2
			}
364 20
		}
365 18
366 18
		return false;
367
	}
368 17
369 17
	/**
370 17
	 * Returns the priority of an item at a particular flattened index.  The index after
371
	 * the last item does not exist but receives a priority from the last item so that
372 20
	 * priority information about any new items being appended is available.
373 1
	 * @param int $index index of the item within the list
374
	 * @param bool $withindex this specifies if the full positional data of the item within the list is returned.
375 20
	 * 		This defaults to false, if no parameter is provided, so only provides the priority number of the item by default.
376
	 * @return array|false|numeric the priority of the item in the list, false if not found.
377
	 *   if $withindex is true, an array is returned of [0 => $priority, 1 => $priorityIndex, 2 => flattenedIndex,
378
	 * 'priority' => $priority, 'index' => $priorityIndex, 'absindex' => flattenedIndex]
379 116
	 */
380
	public function priorityAt($index, $withindex = false)
381 116
	{
382
		if (0 <= $index && $index <= $this->_c) {
383
			$c = $absindex = $index;
384
			$priority = null;
385
			$this->sortPriorities();
386
			foreach (array_keys($this->_d) as $priority) {
387
				if ($index >= ($c = count($this->_d[$priority]))) {
388
					$index -= $c;
389
				} else {
390
					return $withindex ? [$priority, $index, $absindex,
391
							'priority' => $priority, 'index' => $index, 'absindex' => $absindex, ] : $priority;
392
				}
393
			}
394 41
			return $withindex ? [$priority, $c, $absindex,
395
					'priority' => $priority, 'index' => $c, 'absindex' => $absindex, ] : $priority;
396 41
		}
397 1
		return false;
398
	}
399
400 40
	/**
401 40
	 * This inserts an item before another item within the list.  It uses the same priority as the
402 1
	 * found index item and places the new item before it.
403 1
	 * @param mixed $indexitem the item to index
404
	 * @param mixed $item the item to add before indexitem
405 1
	 * @throws TInvalidDataValueException If the item does not exist
406
	 * @return int where the item has been inserted in the flattened list
407 1
	 */
408 1
	public function insertBefore($indexitem, $item)
409
	{
410
		if ($this->getReadOnly()) {
411 40
			throw new TInvalidOperationException('list_readonly', $this::class);
412 40
		}
413
414 2
		if (($priority = $this->priorityOf($indexitem, true)) === false) {
415
			throw new TInvalidDataValueException('list_item_inexistent');
416
		}
417
418
		$this->insertAtIndexInPriority($item, $priority[1], $priority[0]);
419
420
		return $priority[2];
421
	}
422
423
	/**
424
	 * This inserts an item after another item within the list.  It uses the same priority as the
425 5
	 * found index item and places the new item after it.
426
	 * @param mixed $indexitem the item to index
427 5
	 * @param mixed $item the item to add after indexitem
428 1
	 * @throws TInvalidDataValueException If the item does not exist
429
	 * @return int where the item has been inserted in the flattened list
430
	 */
431 4
	public function insertAfter($indexitem, $item)
432 4
	{
433
		if ($this->getReadOnly()) {
434
			throw new TInvalidOperationException('list_readonly', $this::class);
435
		}
436
437
		if (($priority = $this->priorityOf($indexitem, true)) === false) {
438
			throw new TInvalidDataValueException('list_item_inexistent');
439
		}
440
441
		$this->insertAtIndexInPriority($item, $priority[1] + 1, $priority[0]);
442
443
		return $priority[2] + 1;
444
	}
445 51
446
	/**
447 51
	 * Copies iterable data into the priority list.
448 1
	 * Note, existing data in the map will be cleared first.
449
	 * @param mixed $data the data to be copied from, must be an array or object implementing Traversable
450
	 * @throws TInvalidDataTypeException If data is neither an array nor an iterator.
451 50
	 */
452
	public function copyFrom($data): void
453
	{
454 50
		if ($data instanceof TPriorityList) {
455
			if ($this->getCount() > 0) {
456 50
				$this->clear();
457 1
			}
458
			$array = $data->toPriorityArray();
459
			foreach (array_keys($array) as $priority) {
460
				for ($i = 0, $c = count($array[$priority]); $i < $c; $i++) {
461 49
					$this->insertAtIndexInPriority($array[$priority][$i], null, $priority);
462 49
				}
463
			}
464 49
		} elseif ($data instanceof TPriorityMap) {
465 30
			if ($this->getCount() > 0) {
466
				$this->clear();
467
			}
468 49
			$array = $data->toPriorityArray();
469 49
			foreach (array_keys($array) as $priority) {
470 49
				foreach ($array[$priority] as $item) {
471
					$this->insertAtIndexInPriority($item, null, $priority);
472
				}
473
			}
474
		} elseif (is_array($data) || $data instanceof \Traversable) {
475
			if ($this->getCount() > 0) {
476 7
				$this->clear();
477
			}
478 7
			foreach ($data as $item) {
479 1
				$this->insertAtIndexInPriority($item);
480
			}
481
		} elseif ($data !== null) {
482 6
			throw new TInvalidDataTypeException('map_data_not_iterable');
483 6
		}
484 6
	}
485
486 6
	/**
487
	 * Merges iterable data into the priority list.
488 6
	 * New data will be appended to the end of the existing data.  If another TPriorityList is merged,
489
	 * the incoming parameter items will be appended at the priorities they are present.  These items will be added
490
	 * to the end of the existing items with equal priorities, if there are any.
491
	 * @param mixed $data the data to be merged with, must be an array or object implementing Traversable
492
	 * @throws TInvalidDataTypeException If data is neither an array nor an iterator.
493
	 */
494 2
	public function mergeWith($data): void
495
	{
496 2
		if ($data instanceof TPriorityList) {
497
			$array = $data->toPriorityArray();
498
			foreach (array_keys($array) as $priority) {
499
				for ($i = 0, $c = count($array[$priority]); $i < $c; $i++) {
500
					$this->insertAtIndexInPriority($array[$priority][$i], null, $priority);
501
				}
502
			}
503 13
		} elseif ($data instanceof TPriorityMap) {
504
			$array = $data->toPriorityArray();
505 13
			foreach (array_keys($array) as $priority) {
506 11
				foreach ($array[$priority] as $item) {
507
					$this->insertAtIndexInPriority($item, null, $priority);
508 11
				}
509
			}
510
		} elseif (is_array($data) || $data instanceof \Traversable) {
511
			foreach ($data as $item) {
512
				$this->insertAtIndexInPriority($item);
513
			}
514
		} elseif ($data !== null) {
515
			throw new TInvalidDataTypeException('map_data_not_iterable');
516
		}
517
	}
518
519
	/**
520
	 * Returns whether there is an element at the specified offset.
521 48
	 * This method is required by the interface \ArrayAccess.
522
	 * @param mixed $offset the offset to check on
523 48
	 * @return bool
524
	 */
525 48
	public function offsetExists($offset): bool
526 48
	{
527 48
		return ($offset >= 0 && $offset < $this->getCount());
528 46
	}
529 46
530 46
	/**
531
	 * Sets the element at the specified offset. This method is required by the interface \ArrayAccess.
532 11
	 * Setting elements in a priority list is not straight forword when appending and setting at the
533
	 * end boundary.  When appending without an offset (a null offset), the item will be added at
534
	 * the default priority.  The item may not be the last item in the list.  When appending with an
535
	 * offset equal to the count of the list, the item will get be appended with the last items priority.
536 4
	 *
537
	 * All together, when setting the location of an item, the item stays in that location, but appending
538
	 * an item into a priority list doesn't mean the item is at the end of the list.
539
	 * @param int $offset the offset to set element
540
	 * @param mixed $item the element value
541
	 */
542
	public function offsetSet($offset, $item): void
543
	{
544
		if ($offset === null) {
0 ignored issues
show
introduced by
The condition $offset === null is always false.
Loading history...
545
			$this->add($item);
546
			return;
547
		}
548 12
		if (0 <= $offset && $offset <= ($count = $this->getCount())) {
549
			$priority = $this->priorityAt($offset, true);
550 12
			if ($offset !== $count) {
551 4
				$this->removeAtIndexInPriority($priority[1], $priority[0]);
552
			}
553
		} else {
554 12
			throw new TInvalidDataValueException('list_index_invalid', $offset);
555 12
		}
556 12
		$this->insertAtIndexInPriority($item, $priority[1], $priority[0]);
557 12
	}
558 7
559
	/**
560 12
	 * Unsets the element at the specified offset.
561 12
	 * This method is required by the interface \ArrayAccess.
562
	 * @param mixed $offset the offset to unset element
563
	 */
564
	public function offsetUnset($offset): void
565
	{
566
		$this->removeAt($offset);
567
	}
568
569
	/**
570
	 * Returns an array with the names of all variables of this object that should NOT be serialized
571
	 * because their value is the default one or useless to be cached for the next page loads.
572
	 * Reimplement in derived classes to add new variables, but remember to  also to call the parent
573
	 * implementation first.
574
	 * @param array $exprops by reference
575 3
	 * @since 4.2.3
576
	 */
577 3
	protected function _getZappableSleepProps(&$exprops)
578 1
	{
579
		parent::_getZappableSleepProps($exprops);
580
		$this->_priorityZappableSleepProps($exprops);
581 2
	}
582
}
583