39final class ListTag extends Tag implements \Countable, \IteratorAggregate{
40 use NoDynamicFieldsTrait;
53 public function __construct(array $value = [],
int $tagType = NBT::TAG_End){
54 self::restrictArgCount(__METHOD__, func_num_args(), 2);
55 $this->tagType = $tagType;
56 $this->value = new \SplDoublyLinkedList();
57 foreach($value as $tag){
68 foreach($this->value as $v){
82 foreach($this->value as $tag){
83 $result[] = $tag->getValue();
89 public function count() : int{
90 return $this->value->count();
93 public function getCount() : int{
94 return $this->value->count();
101 $this->checkTagType($tag);
102 $this->value->push($tag);
109 return $this->value->pop();
116 $this->checkTagType($tag);
117 $this->value->unshift($tag);
124 return $this->value->shift();
135 $this->checkTagType($tag);
136 $this->value->add($offset, $tag);
142 public function remove(
int $offset) : void{
143 unset($this->value[$offset]);
151 public function get(
int $offset) :
Tag{
152 if(!isset($this->value[$offset])){
153 throw new \OutOfRangeException(
"No such tag at offset $offset");
155 return $this->value[$offset];
162 return $this->value->bottom();
169 return $this->value->top();
177 public function set(
int $offset,
Tag $tag) :
void{
178 $this->checkTagType($tag);
179 $this->value[$offset] = $tag;
185 public function isset(
int $offset) : bool{
186 return isset($this->value[$offset]);
193 return $this->value->isEmpty();
196 protected function getTypeName() : string{
200 public function getType() : int{
201 return
NBT::TAG_List;
208 return $this->tagType;
219 if(!$this->value->isEmpty()){
220 throw new \LogicException(
"Cannot change tag type of non-empty ListTag");
222 $this->tagType = $type;
230 private function checkTagType(
Tag $tag) : void{
231 $type = $tag->getType();
232 if($type !== $this->tagType){
233 if($this->tagType === NBT::TAG_End){
234 $this->tagType = $type;
237 throw new \TypeError(
"Invalid tag of type " . get_class($tag) .
" assigned to ListTag");
242 public static function read(NbtStreamReader $reader, ReaderTracker $tracker) : self{
244 $tagType = $reader->readByte();
245 $size = $reader->readInt();
248 if($tagType === NBT::TAG_End){
249 throw new NbtDataException(
"Unexpected non-empty list of TAG_End");
252 $tracker->protectDepth(
static function() use($size, $tagType, $reader, $tracker, &$value) :
void{
253 for($i = 0; $i < $size; ++$i){
254 $value[] = NBT::createTag($tagType, $reader, $tracker);
258 $tagType = NBT::TAG_End;
260 return new self($value, $tagType);
263 public function write(NbtStreamWriter $writer) : void{
264 $writer->writeByte($this->tagType);
265 $writer->writeInt($this->value->count());
267 foreach($this->value as $tag){
268 $tag->write($writer);
272 protected function stringifyValue(
int $indentation) : string{
275 foreach($this->value as $tag){
276 $str .= str_repeat(
" ", $indentation + 1) . $tag->toString($indentation + 1) .
"\n";
278 return $str . str_repeat(
" ", $indentation) .
"}";
281 public function __clone(){
283 $new = new \SplDoublyLinkedList();
285 foreach($this->value as $tag){
286 $new->push($tag->safeClone());
303 yield from iterator_to_array($this->value, true);
307 if(!($that instanceof $this) or $this->count() !== $that->count()){
311 foreach($this as $k => $v){
312 if(!$v->equals($that->get($k))){