tvm
array.h
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
24 #ifndef TVM_RUNTIME_CONTAINER_ARRAY_H_
25 #define TVM_RUNTIME_CONTAINER_ARRAY_H_
26 
27 #include <algorithm>
28 #include <memory>
29 #include <type_traits>
30 #include <utility>
31 #include <vector>
32 
33 #include "./base.h"
34 #include "./optional.h"
35 
36 namespace tvm {
37 namespace runtime {
38 
40 class ArrayNode : public Object, public InplaceArrayBase<ArrayNode, ObjectRef> {
41  public:
43  size_t size() const { return this->size_; }
44 
50  const ObjectRef at(int64_t i) const { return this->operator[](i); }
51 
53  const ObjectRef* begin() const { return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0)); }
54 
56  const ObjectRef* end() const { return begin() + size_; }
57 
59  void clear() { ShrinkBy(size_); }
60 
66  void SetItem(int64_t i, ObjectRef item) { this->operator[](i) = std::move(item); }
67 
74  static ObjectPtr<ArrayNode> CopyFrom(int64_t cap, ArrayNode* from) {
75  int64_t size = from->size_;
76  ICHECK_GE(cap, size) << "ValueError: not enough capacity";
77  ObjectPtr<ArrayNode> p = ArrayNode::Empty(cap);
78  ObjectRef* write = p->MutableBegin();
79  ObjectRef* read = from->MutableBegin();
80  // To ensure exception safety, size is only incremented after the initialization succeeds
81  for (int64_t& i = p->size_ = 0; i < size; ++i) {
82  new (write++) ObjectRef(*read++);
83  }
84  return p;
85  }
86 
93  static ObjectPtr<ArrayNode> MoveFrom(int64_t cap, ArrayNode* from) {
94  int64_t size = from->size_;
95  ICHECK_GE(cap, size) << "ValueError: not enough capacity";
96  ObjectPtr<ArrayNode> p = ArrayNode::Empty(cap);
97  ObjectRef* write = p->MutableBegin();
98  ObjectRef* read = from->MutableBegin();
99  // To ensure exception safety, size is only incremented after the initialization succeeds
100  for (int64_t& i = p->size_ = 0; i < size; ++i) {
101  new (write++) ObjectRef(std::move(*read++));
102  }
103  from->size_ = 0;
104  return p;
105  }
106 
113  static ObjectPtr<ArrayNode> CreateRepeated(int64_t n, const ObjectRef& val) {
114  ObjectPtr<ArrayNode> p = ArrayNode::Empty(n);
115  ObjectRef* itr = p->MutableBegin();
116  for (int64_t& i = p->size_ = 0; i < n; ++i) {
117  new (itr++) ObjectRef(val);
118  }
119  return p;
120  }
121 
122  static constexpr const uint32_t _type_index = TypeIndex::kRuntimeArray;
123  static constexpr const char* _type_key = "Array";
125 
126  private:
128  size_t GetSize() const { return this->size_; }
129 
131  ObjectRef* MutableBegin() const {
132  return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
133  }
134 
136  ObjectRef* MutableEnd() const { return MutableBegin() + size_; }
137 
143  static ObjectPtr<ArrayNode> Empty(int64_t n = kInitSize) {
144  ICHECK_GE(n, 0);
145  ObjectPtr<ArrayNode> p = make_inplace_array_object<ArrayNode, ObjectRef>(n);
146  p->capacity_ = n;
147  p->size_ = 0;
148  return p;
149  }
150 
159  template <typename IterType>
160  ArrayNode* InitRange(int64_t idx, IterType first, IterType last) {
161  ObjectRef* itr = MutableBegin() + idx;
162  for (; first != last; ++first) {
163  ObjectRef ref = *first;
164  new (itr++) ObjectRef(std::move(ref));
165  }
166  return this;
167  }
168 
176  ArrayNode* MoveElementsLeft(int64_t dst, int64_t src_begin, int64_t src_end) {
177  ObjectRef* from = MutableBegin() + src_begin;
178  ObjectRef* to = MutableBegin() + dst;
179  while (src_begin++ != src_end) {
180  *to++ = std::move(*from++);
181  }
182  return this;
183  }
184 
192  ArrayNode* MoveElementsRight(int64_t dst, int64_t src_begin, int64_t src_end) {
193  ObjectRef* from = MutableBegin() + src_end;
194  ObjectRef* to = MutableBegin() + (src_end - src_begin + dst);
195  while (src_begin++ != src_end) {
196  *--to = std::move(*--from);
197  }
198  return this;
199  }
200 
207  ArrayNode* EnlargeBy(int64_t delta, const ObjectRef& val = ObjectRef(nullptr)) {
208  ObjectRef* itr = MutableEnd();
209  while (delta-- > 0) {
210  new (itr++) ObjectRef(val);
211  ++size_;
212  }
213  return this;
214  }
215 
221  ArrayNode* ShrinkBy(int64_t delta) {
222  ObjectRef* itr = MutableEnd();
223  while (delta-- > 0) {
224  (--itr)->ObjectRef::~ObjectRef();
225  --size_;
226  }
227  return this;
228  }
229 
231  int64_t size_;
232 
234  int64_t capacity_;
235 
237  static constexpr int64_t kInitSize = 4;
238 
240  static constexpr int64_t kIncFactor = 2;
241 
242  // CRTP parent class
244 
245  // Reference class
246  template <typename, typename>
247  friend class Array;
248 
249  // To specialize make_object<ArrayNode>
250  friend ObjectPtr<ArrayNode> make_object<>();
251 };
252 
259 template <typename T, typename IterType>
261  : std::bool_constant<std::is_base_of_v<
262  T, std::remove_cv_t<std::remove_reference_t<decltype(*std::declval<IterType>())>>>> {};
263 
264 template <typename T, typename IterType>
265 struct is_valid_iterator<Optional<T>, IterType> : is_valid_iterator<T, IterType> {};
266 
267 template <typename T, typename IterType>
269 
287 template <typename T,
288  typename = typename std::enable_if<std::is_base_of<ObjectRef, T>::value>::type>
289 class Array : public ObjectRef {
290  public:
291  using value_type = T;
292  // constructors
296  Array() { data_ = ArrayNode::Empty(); }
297 
302  Array(Array<T>&& other) : ObjectRef() { // NOLINT(*)
303  data_ = std::move(other.data_);
304  }
305 
310  Array(const Array<T>& other) : ObjectRef() { // NOLINT(*)
311  data_ = other.data_;
312  }
313 
318  explicit Array(ObjectPtr<Object> n) : ObjectRef(n) {}
319 
326  template <typename IterType>
327  Array(IterType first, IterType last) {
328  Assign(first, last);
329  }
330 
335  Array(std::initializer_list<T> init) { // NOLINT(*)
336  Assign(init.begin(), init.end());
337  }
338 
343  Array(const std::vector<T>& init) { // NOLINT(*)
344  Assign(init.begin(), init.end());
345  }
346 
352  explicit Array(const size_t n, const T& val) { data_ = ArrayNode::CreateRepeated(n, val); }
353 
360  data_ = std::move(other.data_);
361  return *this;
362  }
363 
369  Array<T>& operator=(const Array<T>& other) {
370  data_ = other.data_;
371  return *this;
372  }
373 
374  public:
375  // iterators
376  struct ValueConverter {
377  using ResultType = T;
378  static T convert(const ObjectRef& n) { return DowncastNoCheck<T>(n); }
379  };
380 
383 
385  iterator begin() const { return iterator(GetArrayNode()->begin()); }
386 
388  iterator end() const { return iterator(GetArrayNode()->end()); }
389 
392  // ArrayNode::end() is never nullptr
393  return reverse_iterator(GetArrayNode()->end() - 1);
394  }
395 
398  // ArrayNode::begin() is never nullptr
399  return reverse_iterator(GetArrayNode()->begin() - 1);
400  }
401 
402  public:
403  // const methods in std::vector
409  const T operator[](int64_t i) const {
410  ArrayNode* p = GetArrayNode();
411  ICHECK(p != nullptr) << "ValueError: cannot index a null array";
412  ICHECK(0 <= i && i < p->size_)
413  << "IndexError: indexing " << i << " on an array of size " << p->size_;
414  return DowncastNoCheck<T>(*(p->begin() + i));
415  }
416 
418  size_t size() const {
419  ArrayNode* p = GetArrayNode();
420  return p == nullptr ? 0 : GetArrayNode()->size_;
421  }
422 
424  size_t capacity() const {
425  ArrayNode* p = GetArrayNode();
426  return p == nullptr ? 0 : GetArrayNode()->capacity_;
427  }
428 
430  bool empty() const { return size() == 0; }
431 
433  const T front() const {
434  ArrayNode* p = GetArrayNode();
435  ICHECK(p != nullptr) << "ValueError: cannot index a null array";
436  ICHECK_GT(p->size_, 0) << "IndexError: cannot index an empty array";
437  return DowncastNoCheck<T>(*(p->begin()));
438  }
439 
441  const T back() const {
442  ArrayNode* p = GetArrayNode();
443  ICHECK(p != nullptr) << "ValueError: cannot index a null array";
444  ICHECK_GT(p->size_, 0) << "IndexError: cannot index an empty array";
445  return DowncastNoCheck<T>(*(p->end() - 1));
446  }
447 
448  public:
449  // mutation in std::vector, implements copy-on-write
450 
455  void push_back(const T& item) {
456  ArrayNode* p = CopyOnWrite(1);
457  p->EmplaceInit(p->size_++, item);
458  }
459 
465  void insert(iterator position, const T& val) {
466  ICHECK(data_ != nullptr) << "ValueError: cannot insert a null array";
467  int64_t idx = std::distance(begin(), position);
468  int64_t size = GetArrayNode()->size_;
469  auto addr = CopyOnWrite(1) //
470  ->EnlargeBy(1) //
471  ->MoveElementsRight(idx + 1, idx, size) //
472  ->MutableBegin();
473  new (addr + idx) ObjectRef(val);
474  }
475 
482  template <typename IterType>
483  void insert(iterator position, IterType first, IterType last) {
484  if (first == last) {
485  return;
486  }
487  ICHECK(data_ != nullptr) << "ValueError: cannot insert a null array";
488  int64_t idx = std::distance(begin(), position);
489  int64_t size = GetArrayNode()->size_;
490  int64_t numel = std::distance(first, last);
491  CopyOnWrite(numel)
492  ->EnlargeBy(numel)
493  ->MoveElementsRight(idx + numel, idx, size)
494  ->InitRange(idx, first, last);
495  }
496 
498  void pop_back() {
499  ICHECK(data_ != nullptr) << "ValueError: cannot pop_back because array is null";
500  int64_t size = GetArrayNode()->size_;
501  ICHECK_GT(size, 0) << "ValueError: cannot pop_back because array is empty";
502  CopyOnWrite()->ShrinkBy(1);
503  }
504 
509  void erase(iterator position) {
510  ICHECK(data_ != nullptr) << "ValueError: cannot erase a null array";
511  int64_t st = std::distance(begin(), position);
512  int64_t size = GetArrayNode()->size_;
513  ICHECK(0 <= st && st < size) << "ValueError: cannot erase at index " << st
514  << ", because Array size is " << size;
515  CopyOnWrite() //
516  ->MoveElementsLeft(st, st + 1, size) //
517  ->ShrinkBy(1);
518  }
519 
525  void erase(iterator first, iterator last) {
526  if (first == last) {
527  return;
528  }
529  ICHECK(data_ != nullptr) << "ValueError: cannot erase a null array";
530  int64_t size = GetArrayNode()->size_;
531  int64_t st = std::distance(begin(), first);
532  int64_t ed = std::distance(begin(), last);
533  ICHECK_LT(st, ed) << "ValueError: cannot erase array in range [" << st << ", " << ed << ")";
534  ICHECK(0 <= st && st <= size && 0 <= ed && ed <= size)
535  << "ValueError: cannot erase array in range [" << st << ", " << ed << ")"
536  << ", because array size is " << size;
537  CopyOnWrite() //
538  ->MoveElementsLeft(st, ed, size) //
539  ->ShrinkBy(ed - st);
540  }
541 
546  void resize(int64_t n) {
547  ICHECK_GE(n, 0) << "ValueError: cannot resize an Array to negative size";
548  if (data_ == nullptr) {
549  SwitchContainer(n);
550  return;
551  }
552  int64_t size = GetArrayNode()->size_;
553  if (size < n) {
554  CopyOnWrite(n - size)->EnlargeBy(n - size);
555  } else if (size > n) {
556  CopyOnWrite()->ShrinkBy(size - n);
557  }
558  }
559 
564  void reserve(int64_t n) {
565  if (data_ == nullptr || n > GetArrayNode()->capacity_) {
566  SwitchContainer(n);
567  }
568  }
569 
571  void clear() {
572  if (data_ != nullptr) {
573  ArrayNode* p = CopyOnWrite();
574  p->clear();
575  }
576  }
577 
578  public:
579  // Array's own methods
580 
586  void Set(int64_t i, T value) {
587  ArrayNode* p = this->CopyOnWrite();
588  ICHECK(0 <= i && i < p->size_)
589  << "IndexError: indexing " << i << " on an array of size " << p->size_;
590  *(p->MutableBegin() + i) = std::move(value);
591  }
592 
594  ArrayNode* GetArrayNode() const { return static_cast<ArrayNode*>(data_.get()); }
595 
615  template <typename F, typename U = std::invoke_result_t<F, T>>
616  Array<U> Map(F fmap) const {
617  return Array<U>(MapHelper(data_, fmap));
618  }
619 
626  template <typename F, typename = std::enable_if_t<std::is_same_v<T, std::invoke_result_t<F, T>>>>
627  void MutateByApply(F fmutate) {
628  data_ = MapHelper(std::move(data_), fmutate);
629  }
630 
637  template <typename IterType>
638  void Assign(IterType first, IterType last) {
639  int64_t cap = std::distance(first, last);
640  ICHECK_GE(cap, 0) << "ValueError: cannot construct an Array of negative size";
641  ArrayNode* p = GetArrayNode();
642  if (p != nullptr && data_.unique() && p->capacity_ >= cap) {
643  // do not have to make new space
644  p->clear();
645  } else {
646  // create new space
647  data_ = ArrayNode::Empty(cap);
648  p = GetArrayNode();
649  }
650  // To ensure exception safety, size is only incremented after the initialization succeeds
651  ObjectRef* itr = p->MutableBegin();
652  for (int64_t& i = p->size_ = 0; i < cap; ++i, ++first, ++itr) {
653  new (itr) ObjectRef(*first);
654  }
655  }
656 
666  if (data_ == nullptr) {
667  return SwitchContainer(ArrayNode::kInitSize);
668  }
669  if (!data_.unique()) {
670  return SwitchContainer(capacity());
671  }
672  return static_cast<ArrayNode*>(data_.get());
673  }
674 
677 
678  private:
684  ArrayNode* CopyOnWrite(int64_t reserve_extra) {
685  ArrayNode* p = GetArrayNode();
686  if (p == nullptr) {
687  // necessary to get around the constexpr address issue before c++17
688  const int64_t kInitSize = ArrayNode::kInitSize;
689  return SwitchContainer(std::max(kInitSize, reserve_extra));
690  }
691  if (p->capacity_ >= p->size_ + reserve_extra) {
692  return CopyOnWrite();
693  }
694  int64_t cap = p->capacity_ * ArrayNode::kIncFactor;
695  cap = std::max(cap, p->size_ + reserve_extra);
696  return SwitchContainer(cap);
697  }
698 
703  ArrayNode* SwitchContainer(int64_t capacity) {
704  if (data_ == nullptr) {
705  data_ = ArrayNode::Empty(capacity);
706  } else if (data_.unique()) {
707  data_ = ArrayNode::MoveFrom(capacity, GetArrayNode());
708  } else {
709  data_ = ArrayNode::CopyFrom(capacity, GetArrayNode());
710  }
711  return static_cast<ArrayNode*>(data_.get());
712  }
713 
736  template <typename F, typename U = std::invoke_result_t<F, T>>
737  static ObjectPtr<Object> MapHelper(ObjectPtr<Object> data, F fmap) {
738  if (data == nullptr) {
739  return nullptr;
740  }
741 
742  ICHECK(data->IsInstance<ArrayNode>());
743 
744  constexpr bool is_same_output_type = std::is_same_v<T, U>;
745 
746  if constexpr (is_same_output_type) {
747  if (data.unique()) {
748  // Mutate-in-place path. Only allowed if the output type U is
749  // the same as type T, we have a mutable this*, and there are
750  // no other shared copies of the array.
751  auto arr = static_cast<ArrayNode*>(data.get());
752  for (auto it = arr->MutableBegin(); it != arr->MutableEnd(); it++) {
753  T mapped = fmap(DowncastNoCheck<T>(std::move(*it)));
754  *it = std::move(mapped);
755  }
756  return data;
757  }
758  }
759 
760  constexpr bool compatible_types = is_valid_iterator_v<T, U*> || is_valid_iterator_v<U, T*>;
761 
762  ObjectPtr<ArrayNode> output = nullptr;
763  auto arr = static_cast<ArrayNode*>(data.get());
764 
765  auto it = arr->begin();
766  if constexpr (compatible_types) {
767  // Copy-on-write path, if the output Array<U> might be
768  // represented by the same underlying array as the existing
769  // Array<T>. Typically, this is for functions that map `T` to
770  // `T`, but can also apply to functions that map `T` to
771  // `Optional<T>`, or that map `T` to a subclass or superclass of
772  // `T`.
773  bool all_identical = true;
774  for (; it != arr->end(); it++) {
775  U mapped = fmap(DowncastNoCheck<T>(*it));
776  if (!mapped.same_as(*it)) {
777  // At least one mapped element is different than the
778  // original. Therefore, prepare the output array,
779  // consisting of any previous elements that had mapped to
780  // themselves (if any), and the element that didn't map to
781  // itself.
782  all_identical = false;
783  output = ArrayNode::CreateRepeated(arr->size(), U());
784  output->InitRange(0, arr->begin(), it);
785  output->SetItem(it - arr->begin(), std::move(mapped));
786  it++;
787  break;
788  }
789  }
790  if (all_identical) {
791  return data;
792  }
793  } else {
794  // Path for incompatible types. The constexpr check for
795  // compatible types isn't strictly necessary, as the first
796  // mapped.same_as(*it) would return false, but we might as well
797  // avoid it altogether.
798  output = ArrayNode::CreateRepeated(arr->size(), U());
799  }
800 
801  // Normal path for incompatible types, or post-copy path for
802  // copy-on-write instances.
803  //
804  // If the types are incompatible, then at this point `output` is
805  // empty, and `it` points to the first element of the input.
806  //
807  // If the types were compatible, then at this point `output`
808  // contains zero or more elements that mapped to themselves
809  // followed by the first element that does not map to itself, and
810  // `it` points to the element just after the first element that
811  // does not map to itself. Because at least one element has been
812  // changed, we no longer have the opportunity to avoid a copy, so
813  // we don't need to check the result.
814  //
815  // In both cases, `it` points to the next element to be processed,
816  // so we can either start or resume the iteration from that point,
817  // with no further checks on the result.
818  for (; it != arr->end(); it++) {
819  U mapped = fmap(DowncastNoCheck<T>(*it));
820  output->SetItem(it - arr->begin(), std::move(mapped));
821  }
822 
823  return output;
824  }
825 };
826 
833 template <typename T,
834  typename = typename std::enable_if<std::is_base_of<ObjectRef, T>::value>::type>
835 inline Array<T> Concat(Array<T> lhs, const Array<T>& rhs) {
836  for (const auto& x : rhs) {
837  lhs.push_back(x);
838  }
839  return std::move(lhs);
840 }
841 
842 // Specialize make_object<ArrayNode> to make sure it is correct.
843 template <>
845  return ArrayNode::Empty();
846 }
847 
848 } // namespace runtime
849 
850 // expose the functions to the root namespace.
851 using runtime::Array;
852 using runtime::ArrayNode;
853 } // namespace tvm
854 
855 #endif // TVM_RUNTIME_CONTAINER_ARRAY_H_
void reserve(int64_t n)
Make sure the list has the capacity of at least n.
Definition: array.h:564
static constexpr const uint32_t _type_index
Definition: array.h:122
array node content in array
Definition: array.h:40
const T operator[](int64_t i) const
Immutably read i-th element from array.
Definition: array.h:409
Managed reference to IterSplitExprNode.
Definition: iter_affine_map.h:187
A custom smart pointer for Object.
Definition: object.h:358
Runtime Optional container types.
void insert(iterator position, IterType first, IterType last)
Insert a range of elements into the given position.
Definition: array.h:483
Array(Array< T > &&other)
move constructor
Definition: array.h:302
TVM_DECLARE_FINAL_OBJECT_INFO(ArrayNode, Object)
T ResultType
Definition: array.h:377
void SetItem(int64_t i, ObjectRef item)
Set i-th element of the array in-place.
Definition: array.h:66
const T back() const
Definition: array.h:441
runtime implementation for LibTorch/TorchScript.
Definition: analyzer.h:36
static ObjectPtr< ArrayNode > CopyFrom(int64_t cap, ArrayNode *from)
Constructs a container and copy from another.
Definition: array.h:74
bool empty() const
Definition: array.h:430
iterator adapter that adapts TIter to return another type.
Definition: base.h:241
void resize(int64_t n)
Resize the array.
Definition: array.h:546
size_t size() const
Definition: array.h:43
Base utilities for common POD(plain old data) container types.
const ObjectRef * end() const
Definition: array.h:56
Array(const size_t n, const T &val)
Constructs a container with n elements. Each element is a copy of val.
Definition: array.h:352
friend ObjectPtr< ArrayNode > make_object()
Definition: array.h:844
ArrayNode * GetArrayNode() const
Definition: array.h:594
base class of all object containers.
Definition: object.h:167
Array()
default constructor
Definition: array.h:296
void Set(int64_t i, T value)
set i-th element of the array.
Definition: array.h:586
Array< T > & operator=(const Array< T > &other)
copy assign operator
Definition: array.h:369
void push_back(const T &item)
push a new item to the back of the list
Definition: array.h:455
Base template for classes with array like memory layout.
Definition: base.h:100
const ObjectRef * begin() const
Definition: array.h:53
void insert(iterator position, const T &val)
Insert an element into the given position.
Definition: array.h:465
size_t size() const
Definition: array.h:418
const T front() const
Definition: array.h:433
void erase(iterator position)
Erase an element on the given position.
Definition: array.h:509
Array, container representing a contiguous sequence of ObjectRefs.
Definition: array.h:289
bool unique() const
Definition: object.h:862
ObjectPtr< Object > data_
Internal pointer that backs the reference.
Definition: object.h:574
Array(const Array< T > &other)
copy constructor
Definition: array.h:310
void erase(iterator first, iterator last)
Erase a given range of elements.
Definition: array.h:525
PrimExpr max(PrimExpr a, PrimExpr b, Span span=Span())
take maximum of two values
void clear()
Release reference to all the elements.
Definition: array.h:59
reverse_iterator rbegin() const
Definition: array.h:391
void * AddressOf(size_t idx) const
Return the raw pointer to the element at idx.
Definition: base.h:169
Array(IterType first, IterType last)
Constructor from iterator.
Definition: array.h:327
iterator end() const
Definition: array.h:388
Base class of all object reference.
Definition: object.h:511
Array(const std::vector< T > &init)
constructor from vector
Definition: array.h:343
iterator begin() const
Definition: array.h:385
T * get() const
Definition: object.h:411
ArrayNode * CopyOnWrite()
Copy on write semantics Do nothing if current handle is the unique copy of the array. Otherwise make a new copy of the array to ensure the current handle hold a unique copy.
Definition: array.h:665
Array< T > & operator=(Array< T > &&other)
move assign operator
Definition: array.h:359
iterator adapter that adapts TIter to return another type.
Definition: base.h:188
bool unique() const
Definition: object.h:458
static constexpr const char * _type_key
Definition: array.h:123
Helper struct for type-checking.
Definition: array.h:260
void MutateByApply(F fmutate)
Helper function to apply fmutate to mutate an array.
Definition: array.h:627
runtime::Array.
Definition: object.h:68
const ObjectRef at(int64_t i) const
Read i-th element from array.
Definition: array.h:50
size_t capacity() const
Definition: array.h:424
const ObjectRef & operator[](size_t idx) const
Access element at index.
Definition: base.h:107
Optional container that to represent to a Nullable variant of T.
Definition: optional.h:51
void pop_back()
Remove the last item of the list.
Definition: array.h:498
reverse_iterator rend() const
Definition: array.h:397
void Assign(IterType first, IterType last)
reset the array to content from iterator.
Definition: array.h:638
static T convert(const ObjectRef &n)
Definition: array.h:378
constexpr bool is_valid_iterator_v
Definition: array.h:268
Array(std::initializer_list< T > init)
constructor from initializer list
Definition: array.h:335
void EmplaceInit(size_t idx, Args &&... args)
Construct a value in place with the arguments.
Definition: base.h:149
Array< U > Map(F fmap) const
Helper function to apply a map function onto the array.
Definition: array.h:616
static ObjectPtr< ArrayNode > CreateRepeated(int64_t n, const ObjectRef &val)
Constructs a container with n elements. Each element is a copy of val.
Definition: array.h:113
Array(ObjectPtr< Object > n)
constructor from pointer
Definition: array.h:318
Array< T > Concat(Array< T > lhs, const Array< T > &rhs)
Concat two Arrays.
Definition: array.h:835
void clear()
Release reference to all the elements.
Definition: array.h:571
static ObjectPtr< ArrayNode > MoveFrom(int64_t cap, ArrayNode *from)
Constructs a container and move from another.
Definition: array.h:93