47final class ListTag extends Tag implements \Countable, \IteratorAggregate{
48 use NoDynamicFieldsTrait;
61 public function __construct(array $value = [],
int $tagType = NBT::TAG_End){
62 self::restrictArgCount(__METHOD__, func_num_args(), 2);
63 $this->tagType = $tagType;
64 foreach($value as $tag){
83 return array_map(fn(
Tag $t) => $t->getValue(), $this->value);
86 public function count() : int{
87 return count($this->value);
90 public function getCount() : int{
91 return count($this->value);
98 $this->checkTagType($tag);
99 $this->value[] = $tag;
106 if(count($this->value) === 0){
107 throw new \LogicException(
"List is empty");
109 return array_pop($this->value);
116 $this->checkTagType($tag);
117 array_unshift($this->value, $tag);
124 if(count($this->value) === 0){
125 throw new \LogicException(
"List is empty");
127 return array_shift($this->value);
138 $this->checkTagType($tag);
139 if($offset < 0 || $offset > count($this->value)){
140 throw new \OutOfRangeException(
"Offset cannot be negative or larger than the list's current size");
142 $newValue = array_slice($this->value, 0, $offset);
144 array_push($newValue, ...array_slice($this->value, $offset));
145 $this->value = $newValue;
151 public function remove(
int $offset) : void{
153 $newValue = $this->value;
154 unset($newValue[$offset]);
155 $this->value = array_values($newValue);
163 public function get(
int $offset) :
Tag{
164 if(!isset($this->value[$offset])){
165 throw new \OutOfRangeException(
"No such tag at offset $offset");
167 return $this->value[$offset];
174 if(count($this->value) === 0){
175 throw new \LogicException(
"List is empty");
177 return $this->value[0];
184 if(count($this->value) === 0){
185 throw new \LogicException(
"List is empty");
187 return $this->value[array_key_last($this->value)];
195 public function set(
int $offset,
Tag $tag) : void{
196 $this->checkTagType($tag);
197 if($offset < 0 || $offset > count($this->value)){
198 throw new \OutOfRangeException(
"Offset cannot be negative or larger than the list's current size");
200 $this->value[$offset] = $tag;
206 public function isset(
int $offset) : bool{
207 return isset($this->value[$offset]);
214 return count($this->value) === 0;
217 protected function getTypeName() : string{
221 public function getType() : int{
222 return
NBT::TAG_List;
229 return $this->tagType;
243 if(count($this->value) > 0){
244 throw new \LogicException(
"Cannot change tag type of non-empty ListTag");
246 $this->tagType = $type;
254 private function checkTagType(
Tag $tag) : void{
255 $type = $tag->getType();
256 if($type !== $this->tagType){
257 if(count($this->value) === 0){
258 $this->tagType = $type;
260 throw new \TypeError(
"Invalid tag of type " . get_class($tag) .
" assigned to ListTag, expected " . get_class($this->value[0]));
265 public static function read(NbtStreamReader $reader, ReaderTracker $tracker) : self{
267 $tagType = $reader->readByte();
268 $size = $reader->readInt();
271 if($tagType === NBT::TAG_End){
272 throw new NbtDataException(
"Unexpected non-empty list of TAG_End");
275 $tracker->protectDepth(
static function() use($size, $tagType, $reader, $tracker, &$value) :
void{
276 for($i = 0; $i < $size; ++$i){
277 $value[] = NBT::createTag($tagType, $reader, $tracker);
281 return new self($value, $tagType);
284 public function write(NbtStreamWriter $writer) : void{
285 $writer->writeByte($this->tagType);
286 $writer->writeInt(count($this->value));
287 foreach($this->value as $tag){
288 $tag->write($writer);
292 protected function stringifyValue(
int $indentation) : string{
294 foreach($this->value as $tag){
295 $str .= str_repeat(
" ", $indentation + 1) . $tag->toString($indentation + 1) .
"\n";
297 return $str . str_repeat(
" ", $indentation) .
"}";
300 public function __clone(){
301 $this->value = array_map(fn(Tag $t) => $t->safeClone(), $this->value);
313 yield from $this->value;
317 if(!($that instanceof $this) or count($this->value) !== count($that->value)){
321 foreach($this->value as $k => $v){
322 if(!$v->equals($that->value[$k])){