22declare(strict_types=1);
24namespace pocketmine\nbt\tag;
31use
function func_num_args;
32use
function get_class;
33use
function iterator_to_array;
34use
function str_repeat;
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){
67 foreach($this->value as $k => $v){
81 foreach($this->value as $tag){
82 $result[] = $tag->getValue();
88 public function count() : int{
89 return $this->value->count();
92 public function getCount() : int{
93 return $this->value->count();
100 $this->checkTagType($tag);
101 $this->value->push($tag);
108 return $this->value->pop();
115 $this->checkTagType($tag);
116 $this->value->unshift($tag);
123 return $this->value->shift();
134 $this->checkTagType($tag);
135 $this->value->add($offset, $tag);
141 public function remove(
int $offset) :
void{
142 unset($this->value[$offset]);
150 public function get(
int $offset) :
Tag{
151 if(!isset($this->value[$offset])){
152 throw new \OutOfRangeException(
"No such tag at offset $offset");
154 return $this->value[$offset];
161 return $this->value->bottom();
168 return $this->value->top();
176 public function set(
int $offset,
Tag $tag) :
void{
177 $this->checkTagType($tag);
178 $this->value[$offset] = $tag;
184 public function isset(
int $offset) : bool{
185 return isset($this->value[$offset]);
192 return $this->value->isEmpty();
195 protected function getTypeName() : string{
199 public function getType() : int{
200 return
NBT::TAG_List;
207 return $this->tagType;
218 if(!$this->value->isEmpty()){
219 throw new \LogicException(
"Cannot change tag type of non-empty ListTag");
221 $this->tagType = $type;
229 private function checkTagType(
Tag $tag) : void{
230 $type = $tag->getType();
231 if($type !== $this->tagType){
232 if($this->tagType === NBT::TAG_End){
233 $this->tagType = $type;
236 throw new \TypeError(
"Invalid tag of type " . get_class($tag) .
" assigned to ListTag");
241 public static function read(NbtStreamReader $reader, ReaderTracker $tracker) : self{
243 $tagType = $reader->readByte();
244 $size = $reader->readInt();
247 if($tagType === NBT::TAG_End){
248 throw new NbtDataException(
"Unexpected non-empty list of TAG_End");
251 $tracker->protectDepth(
static function() use($size, $tagType, $reader, $tracker, &$value) :
void{
252 for($i = 0; $i < $size; ++$i){
253 $value[] = NBT::createTag($tagType, $reader, $tracker);
257 $tagType = NBT::TAG_End;
259 return new self($value, $tagType);
262 public function write(NbtStreamWriter $writer) : void{
263 $writer->writeByte($this->tagType);
264 $writer->writeInt($this->value->count());
266 foreach($this->value as $tag){
267 $tag->write($writer);
271 protected function stringifyValue(
int $indentation) : string{
274 foreach($this->value as $tag){
275 $str .= str_repeat(
" ", $indentation + 1) . $tag->toString($indentation + 1) .
"\n";
277 return $str . str_repeat(
" ", $indentation) .
"}";
280 public function __clone(){
282 $new = new \SplDoublyLinkedList();
284 foreach($this->value as $tag){
285 $new->push($tag->safeClone());
302 yield from iterator_to_array($this->value, true);
306 if(!($that instanceof $this) or $this->count() !== $that->count()){
310 foreach($this as $k => $v){
311 if(!$v->equals($that->get($k))){
__construct(array $value=[], int $tagType=NBT::TAG_End)
insert(int $offset, Tag $tag)