1<?php 2 3/** 4 * This file is part of the Nette Framework (https://nette.org) 5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com) 6 */ 7 8declare(strict_types=1); 9 10namespace Nette\Utils; 11 12use Nette; 13 14 15/** 16 * Provides the base class for a generic list (items can be accessed by index). 17 * @template T 18 * @implements \IteratorAggregate<int, T> 19 * @implements \ArrayAccess<int, T> 20 */ 21class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate 22{ 23 use Nette\SmartObject; 24 25 private array $list = []; 26 27 28 /** 29 * Transforms array to ArrayList. 30 * @param list<T> $array 31 */ 32 public static function from(array $array): static 33 { 34 if (!Arrays::isList($array)) { 35 throw new Nette\InvalidArgumentException('Array is not valid list.'); 36 } 37 38 $obj = new static; 39 $obj->list = $array; 40 return $obj; 41 } 42 43 44 /** 45 * Returns an iterator over all items. 46 * @return \Iterator<int, T> 47 */ 48 public function &getIterator(): \Iterator 49 { 50 foreach ($this->list as &$item) { 51 yield $item; 52 } 53 } 54 55 56 /** 57 * Returns items count. 58 */ 59 public function count(): int 60 { 61 return count($this->list); 62 } 63 64 65 /** 66 * Replaces or appends a item. 67 * @param int|null $index 68 * @param T $value 69 * @throws Nette\OutOfRangeException 70 */ 71 public function offsetSet($index, $value): void 72 { 73 if ($index === null) { 74 $this->list[] = $value; 75 76 } elseif (!is_int($index) || $index < 0 || $index >= count($this->list)) { 77 throw new Nette\OutOfRangeException('Offset invalid or out of range'); 78 79 } else { 80 $this->list[$index] = $value; 81 } 82 } 83 84 85 /** 86 * Returns a item. 87 * @param int $index 88 * @return T 89 * @throws Nette\OutOfRangeException 90 */ 91 public function offsetGet($index): mixed 92 { 93 if (!is_int($index) || $index < 0 || $index >= count($this->list)) { 94 throw new Nette\OutOfRangeException('Offset invalid or out of range'); 95 } 96 97 return $this->list[$index]; 98 } 99 100 101 /** 102 * Determines whether a item exists. 103 * @param int $index 104 */ 105 public function offsetExists($index): bool 106 { 107 return is_int($index) && $index >= 0 && $index < count($this->list); 108 } 109 110 111 /** 112 * Removes the element at the specified position in this list. 113 * @param int $index 114 * @throws Nette\OutOfRangeException 115 */ 116 public function offsetUnset($index): void 117 { 118 if (!is_int($index) || $index < 0 || $index >= count($this->list)) { 119 throw new Nette\OutOfRangeException('Offset invalid or out of range'); 120 } 121 122 array_splice($this->list, $index, 1); 123 } 124 125 126 /** 127 * Prepends a item. 128 * @param T $value 129 */ 130 public function prepend(mixed $value): void 131 { 132 $first = array_slice($this->list, 0, 1); 133 $this->offsetSet(0, $value); 134 array_splice($this->list, 1, 0, $first); 135 } 136} 137