You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tvm.apache.org by GitBox <gi...@apache.org> on 2020/05/15 21:51:26 UTC

[GitHub] [incubator-tvm] zhiics commented on a change in pull request #5585: [Runtime] Introduce runtime::Array

zhiics commented on a change in pull request #5585:
URL: https://github.com/apache/incubator-tvm/pull/5585#discussion_r426044392



##########
File path: include/tvm/runtime/container.h
##########
@@ -188,6 +188,709 @@ class InplaceArrayBase {
     return data_start + idx * sizeof(ElemType);
   }
 };
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+namespace runtime {
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class IterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit IterAdapter(TIter iter) : iter_(iter) {}
+  inline IterAdapter& operator++() {
+    ++iter_;
+    return *this;
+  }
+  inline IterAdapter& operator--() {
+    --iter_;
+    return *this;
+  }
+  inline IterAdapter& operator++(int) {
+    IterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline IterAdapter& operator--(int) {
+    IterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+
+  inline IterAdapter operator+(difference_type offset) const { return IterAdapter(iter_ + offset); }
+
+  template <typename T = IterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const IterAdapter& rhs) const {
+    return iter_ - rhs.iter_;
+  }
+
+  inline bool operator==(IterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(IterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class ReverseIterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit ReverseIterAdapter(TIter iter) : iter_(iter) {}
+  inline ReverseIterAdapter& operator++() {
+    --iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator--() {
+    ++iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator++(int) {
+    ReverseIterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter& operator--(int) {
+    ReverseIterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter operator+(difference_type offset) const {
+    return ReverseIterAdapter(iter_ - offset);
+  }
+
+  template <typename T = ReverseIterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const ReverseIterAdapter& rhs) const {
+    return rhs.iter_ - iter_;
+  }
+
+  inline bool operator==(ReverseIterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(ReverseIterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+
+// forward-declare a friend method of ArrayNode.
+TVM_DLL runtime::ObjectRef LoadJSON(std::string json_str);
+
+namespace runtime {
+
+/*! \brief array node content in array */
+class ArrayNode : public Object, public InplaceArrayBase<ArrayNode, ObjectRef> {
+ public:
+  /*! \return The size of the array */
+  inline size_t size() const { return this->size_; }
+
+  /*!
+   * \brief Read i-th element from array.
+   * \param i The index
+   * \return the i-th element.
+   */
+  inline const ObjectRef at(const int64_t i) const { return this->operator[](i); }
+
+  /*! \return begin constant iterator */
+  inline const ObjectRef* begin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end constant iterator */
+  inline const ObjectRef* end() const { return begin() + size_; }
+
+  /*!
+   * \brief Set i-th element of the array in-place
+   * \param i The index
+   * \param item The value to be set
+   */
+  inline void SetItem(const int64_t i, ObjectRef item) { this->operator[](i) = std::move(item); }
+
+  static constexpr const uint32_t _type_index = TypeIndex::kRuntimeArray;
+  static constexpr const char* _type_key = "Array";
+  TVM_DECLARE_FINAL_OBJECT_INFO(ArrayNode, Object);
+
+ private:
+  /*! \return Size of initialized memory, used by InplaceArrayBase. */
+  size_t GetSize() const { return this->size_; }
+
+  /*!
+   * \brief Create an ArrayNode with the given capacity.
+   * \param cap Required capacity
+   * \return Ref-counted ArrayNode requested
+   */
+  static inline ObjectPtr<ArrayNode> make(const int64_t cap = INIT_SIZE) {
+    ObjectPtr<ArrayNode> p = make_inplace_array_object<ArrayNode, ObjectRef>(cap);
+    p->capacity_ = cap;
+    p->size_ = 0;
+    return p;
+  }
+
+  /*! \return begin mutable iterator */
+  inline ObjectRef* MutableBegin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end mutable iterator */
+  inline ObjectRef* MutableEnd() const { return MutableBegin() + size_; }
+
+  /*! \brief Release reference to all the elements */
+  inline void clear() {
+    for (ObjectRef* itr = MutableEnd(); size_; --size_) {
+      (*--itr).~ObjectRef();
+    }
+  }
+
+  /*! \brief Number of elements used */
+  int64_t size_;
+
+  /*! \brief Number of elements allocated */
+  int64_t capacity_;
+
+  /*! \brief Initial size of ArrayNode */
+  static const constexpr int64_t INIT_SIZE = 16;
+
+  /*! \brief Expansion factor of the Array */
+  static const constexpr int64_t INC_FACTOR = 2;
+
+  // CRTP parent class
+  friend InplaceArrayBase<ArrayNode, ObjectRef>;
+
+  // Reference class
+  template <typename, typename>
+  friend class Array;
+
+  // To specialize make_object<ArrayNode>
+  friend ObjectPtr<ArrayNode> make_object<>();
+
+  // This method requires access to `size_` and `make`
+  friend ObjectRef tvm::LoadJSON(std::string json_str);
+};
+
+/*!
+ * \brief Array container of ObjectRef in DSL graph.
+ *  Array implements copy-on-write semantics, which means array is mutable
+ *  but copy will happen when array is referenced in more than two places.
+ *
+ * operator[] only provide const acces, use Set to mutate the content.

Review comment:
       s/acces/access

##########
File path: include/tvm/runtime/container.h
##########
@@ -188,6 +188,709 @@ class InplaceArrayBase {
     return data_start + idx * sizeof(ElemType);
   }
 };
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+namespace runtime {
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class IterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit IterAdapter(TIter iter) : iter_(iter) {}
+  inline IterAdapter& operator++() {
+    ++iter_;
+    return *this;
+  }
+  inline IterAdapter& operator--() {
+    --iter_;
+    return *this;
+  }
+  inline IterAdapter& operator++(int) {
+    IterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline IterAdapter& operator--(int) {
+    IterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+
+  inline IterAdapter operator+(difference_type offset) const { return IterAdapter(iter_ + offset); }
+
+  template <typename T = IterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const IterAdapter& rhs) const {
+    return iter_ - rhs.iter_;
+  }
+
+  inline bool operator==(IterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(IterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class ReverseIterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit ReverseIterAdapter(TIter iter) : iter_(iter) {}
+  inline ReverseIterAdapter& operator++() {
+    --iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator--() {
+    ++iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator++(int) {
+    ReverseIterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter& operator--(int) {
+    ReverseIterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter operator+(difference_type offset) const {
+    return ReverseIterAdapter(iter_ - offset);
+  }
+
+  template <typename T = ReverseIterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const ReverseIterAdapter& rhs) const {
+    return rhs.iter_ - iter_;
+  }
+
+  inline bool operator==(ReverseIterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(ReverseIterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+
+// forward-declare a friend method of ArrayNode.
+TVM_DLL runtime::ObjectRef LoadJSON(std::string json_str);
+
+namespace runtime {
+
+/*! \brief array node content in array */
+class ArrayNode : public Object, public InplaceArrayBase<ArrayNode, ObjectRef> {
+ public:
+  /*! \return The size of the array */
+  inline size_t size() const { return this->size_; }
+
+  /*!
+   * \brief Read i-th element from array.
+   * \param i The index
+   * \return the i-th element.
+   */
+  inline const ObjectRef at(const int64_t i) const { return this->operator[](i); }
+
+  /*! \return begin constant iterator */
+  inline const ObjectRef* begin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end constant iterator */
+  inline const ObjectRef* end() const { return begin() + size_; }
+
+  /*!
+   * \brief Set i-th element of the array in-place
+   * \param i The index
+   * \param item The value to be set
+   */
+  inline void SetItem(const int64_t i, ObjectRef item) { this->operator[](i) = std::move(item); }
+
+  static constexpr const uint32_t _type_index = TypeIndex::kRuntimeArray;
+  static constexpr const char* _type_key = "Array";
+  TVM_DECLARE_FINAL_OBJECT_INFO(ArrayNode, Object);
+
+ private:
+  /*! \return Size of initialized memory, used by InplaceArrayBase. */
+  size_t GetSize() const { return this->size_; }
+
+  /*!
+   * \brief Create an ArrayNode with the given capacity.
+   * \param cap Required capacity
+   * \return Ref-counted ArrayNode requested
+   */
+  static inline ObjectPtr<ArrayNode> make(const int64_t cap = INIT_SIZE) {
+    ObjectPtr<ArrayNode> p = make_inplace_array_object<ArrayNode, ObjectRef>(cap);
+    p->capacity_ = cap;
+    p->size_ = 0;
+    return p;
+  }
+
+  /*! \return begin mutable iterator */
+  inline ObjectRef* MutableBegin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end mutable iterator */
+  inline ObjectRef* MutableEnd() const { return MutableBegin() + size_; }
+
+  /*! \brief Release reference to all the elements */
+  inline void clear() {
+    for (ObjectRef* itr = MutableEnd(); size_; --size_) {
+      (*--itr).~ObjectRef();
+    }
+  }
+
+  /*! \brief Number of elements used */
+  int64_t size_;
+
+  /*! \brief Number of elements allocated */
+  int64_t capacity_;
+
+  /*! \brief Initial size of ArrayNode */
+  static const constexpr int64_t INIT_SIZE = 16;
+
+  /*! \brief Expansion factor of the Array */
+  static const constexpr int64_t INC_FACTOR = 2;
+
+  // CRTP parent class
+  friend InplaceArrayBase<ArrayNode, ObjectRef>;
+
+  // Reference class
+  template <typename, typename>
+  friend class Array;
+
+  // To specialize make_object<ArrayNode>
+  friend ObjectPtr<ArrayNode> make_object<>();
+
+  // This method requires access to `size_` and `make`
+  friend ObjectRef tvm::LoadJSON(std::string json_str);
+};
+
+/*!
+ * \brief Array container of ObjectRef in DSL graph.
+ *  Array implements copy-on-write semantics, which means array is mutable
+ *  but copy will happen when array is referenced in more than two places.
+ *
+ * operator[] only provide const acces, use Set to mutate the content.
+ * \tparam T The content ObjectRef type.
+ */
+template <typename T,
+          typename = typename std::enable_if<std::is_base_of<ObjectRef, T>::value>::type>
+class Array : public ObjectRef {
+ public:
+  // constructors
+  /*!
+   * \brief default constructor
+   */
+  Array() { data_ = ArrayNode::make(); }
+
+  /*!
+   * \brief move constructor
+   * \param other source
+   */
+  Array(Array<T>&& other) : ObjectRef() {  // NOLINT(*)
+    data_ = std::move(other.data_);
+  }
+
+  /*!
+   * \brief copy constructor
+   * \param other source
+   */
+  Array(const Array<T>& other) : ObjectRef() {  // NOLINT(*)
+    data_ = other.data_;
+  }
+
+  /*!
+   * \brief constructor from pointer
+   * \param n the container pointer
+   */
+  explicit Array(ObjectPtr<Object> n) : ObjectRef(n) {}
+
+  /*!
+   * \brief constructor from iterator
+   * \param begin begin of iterator
+   * \param end end of iterator
+   * \tparam IterType The type of iterator
+   */
+  template <typename IterType>
+  Array(IterType begin, IterType end) {
+    Assign(begin, end);
+  }
+
+  /*!
+   * \brief constructor from initializer list
+   * \param init The initalizer list
+   */
+  Array(std::initializer_list<T> init) {  // NOLINT(*)
+    Assign(init.begin(), init.end());
+  }
+
+  /*!
+   * \brief constructor from vector
+   * \param init The vector
+   */
+  Array(const std::vector<T>& init) {  // NOLINT(*)
+    Assign(init.begin(), init.end());
+  }
+
+  /*!
+   * \brief Constructs a container with n elements. Each element is a copy of val
+   * \param n The size of the container
+   * \param val The init value
+   */
+  explicit Array(const size_t n, const T& val) {
+    ObjectPtr<ArrayNode> p = ArrayNode::make(static_cast<int64_t>(n));
+    for (int64_t& i = p->size_ = 0; i < static_cast<int64_t>(n); ++i) {
+      p->EmplaceInit(i, val);
+    }
+    data_ = std::move(p);
+  }
+
+  /*!
+   * \brief move assign operator
+   * \param other The source of assignment
+   * \return reference to self.
+   */
+  Array<T>& operator=(Array<T>&& other) {
+    data_ = std::move(other.data_);
+    return *this;
+  }
+
+  /*!
+   * \brief copy assign operator
+   * \param other The source of assignment
+   * \return reference to self.
+   */
+  Array<T>& operator=(const Array<T>& other) {
+    data_ = other.data_;
+    return *this;
+  }
+
+ public:
+  // iterators
+  struct ValueConverter {
+    using ResultType = T;
+    static inline T convert(const ObjectRef& n) { return DowncastNoCheck<T>(n); }
+  };
+
+  using iterator = IterAdapter<ValueConverter, const ObjectRef*>;
+  using reverse_iterator = ReverseIterAdapter<ValueConverter, const ObjectRef*>;
+
+  /*! \return begin iterator */
+  inline iterator begin() const { return iterator(GetArrayNode()->begin()); }
+
+  /*! \return end iterator */
+  inline iterator end() const { return iterator(GetArrayNode()->end()); }
+
+  /*! \return rbegin iterator */
+  inline reverse_iterator rbegin() const { return reverse_iterator(GetArrayNode()->end() - 1); }
+
+  /*! \return rend iterator */
+  inline reverse_iterator rend() const { return reverse_iterator(GetArrayNode()->begin() - 1); }
+
+ public:
+  // const methods in std::vector
+  /*!
+   * \brief Immutably read i-th element from array.
+   * \param i The index
+   * \return the i-th element.
+   */
+  inline const T operator[](const int64_t i) const {
+    ArrayNode* data = GetArrayNode();
+    CHECK(data != nullptr) << "ValueError: cannot index a null Array";
+    return DowncastNoCheck<T>((*data)[i]);
+  }
+
+  /*! \return The size of the array */
+  inline size_t size() const {
+    ArrayNode* p = GetArrayNode();
+    return p == nullptr ? 0 : GetArrayNode()->size_;
+  }
+

Review comment:
       would it be useful to have helpers like `front` and `back`? `back` is probably more useful though. 

##########
File path: tests/scripts/task_python_frontend.sh
##########
@@ -26,6 +26,7 @@ export OMP_NUM_THREADS=1
 
 find . -type f -path "*.pyc" | xargs rm -f
 
+ulimit -s 819600

Review comment:
       BTW, why do we need to increase the stack size here? Is it because some relay passes are failing due to stack overflow?

##########
File path: include/tvm/runtime/container.h
##########
@@ -188,6 +188,709 @@ class InplaceArrayBase {
     return data_start + idx * sizeof(ElemType);
   }
 };
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+namespace runtime {
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class IterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit IterAdapter(TIter iter) : iter_(iter) {}
+  inline IterAdapter& operator++() {
+    ++iter_;
+    return *this;
+  }
+  inline IterAdapter& operator--() {
+    --iter_;
+    return *this;
+  }
+  inline IterAdapter& operator++(int) {
+    IterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline IterAdapter& operator--(int) {
+    IterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+
+  inline IterAdapter operator+(difference_type offset) const { return IterAdapter(iter_ + offset); }
+
+  template <typename T = IterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const IterAdapter& rhs) const {
+    return iter_ - rhs.iter_;
+  }
+
+  inline bool operator==(IterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(IterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class ReverseIterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit ReverseIterAdapter(TIter iter) : iter_(iter) {}
+  inline ReverseIterAdapter& operator++() {
+    --iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator--() {
+    ++iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator++(int) {
+    ReverseIterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter& operator--(int) {
+    ReverseIterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter operator+(difference_type offset) const {
+    return ReverseIterAdapter(iter_ - offset);
+  }
+
+  template <typename T = ReverseIterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const ReverseIterAdapter& rhs) const {
+    return rhs.iter_ - iter_;
+  }
+
+  inline bool operator==(ReverseIterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(ReverseIterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+
+// forward-declare a friend method of ArrayNode.
+TVM_DLL runtime::ObjectRef LoadJSON(std::string json_str);
+
+namespace runtime {
+
+/*! \brief array node content in array */
+class ArrayNode : public Object, public InplaceArrayBase<ArrayNode, ObjectRef> {
+ public:
+  /*! \return The size of the array */
+  inline size_t size() const { return this->size_; }
+
+  /*!
+   * \brief Read i-th element from array.
+   * \param i The index
+   * \return the i-th element.
+   */
+  inline const ObjectRef at(const int64_t i) const { return this->operator[](i); }
+
+  /*! \return begin constant iterator */
+  inline const ObjectRef* begin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end constant iterator */
+  inline const ObjectRef* end() const { return begin() + size_; }
+
+  /*!
+   * \brief Set i-th element of the array in-place
+   * \param i The index
+   * \param item The value to be set
+   */
+  inline void SetItem(const int64_t i, ObjectRef item) { this->operator[](i) = std::move(item); }
+
+  static constexpr const uint32_t _type_index = TypeIndex::kRuntimeArray;
+  static constexpr const char* _type_key = "Array";
+  TVM_DECLARE_FINAL_OBJECT_INFO(ArrayNode, Object);
+
+ private:
+  /*! \return Size of initialized memory, used by InplaceArrayBase. */
+  size_t GetSize() const { return this->size_; }
+
+  /*!
+   * \brief Create an ArrayNode with the given capacity.
+   * \param cap Required capacity
+   * \return Ref-counted ArrayNode requested
+   */
+  static inline ObjectPtr<ArrayNode> make(const int64_t cap = INIT_SIZE) {
+    ObjectPtr<ArrayNode> p = make_inplace_array_object<ArrayNode, ObjectRef>(cap);
+    p->capacity_ = cap;
+    p->size_ = 0;
+    return p;
+  }
+
+  /*! \return begin mutable iterator */
+  inline ObjectRef* MutableBegin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end mutable iterator */
+  inline ObjectRef* MutableEnd() const { return MutableBegin() + size_; }
+
+  /*! \brief Release reference to all the elements */
+  inline void clear() {
+    for (ObjectRef* itr = MutableEnd(); size_; --size_) {
+      (*--itr).~ObjectRef();
+    }
+  }
+
+  /*! \brief Number of elements used */
+  int64_t size_;
+
+  /*! \brief Number of elements allocated */
+  int64_t capacity_;
+
+  /*! \brief Initial size of ArrayNode */
+  static const constexpr int64_t INIT_SIZE = 16;
+
+  /*! \brief Expansion factor of the Array */
+  static const constexpr int64_t INC_FACTOR = 2;
+
+  // CRTP parent class
+  friend InplaceArrayBase<ArrayNode, ObjectRef>;
+
+  // Reference class
+  template <typename, typename>
+  friend class Array;
+
+  // To specialize make_object<ArrayNode>
+  friend ObjectPtr<ArrayNode> make_object<>();
+
+  // This method requires access to `size_` and `make`
+  friend ObjectRef tvm::LoadJSON(std::string json_str);
+};
+
+/*!
+ * \brief Array container of ObjectRef in DSL graph.
+ *  Array implements copy-on-write semantics, which means array is mutable
+ *  but copy will happen when array is referenced in more than two places.
+ *
+ * operator[] only provide const acces, use Set to mutate the content.
+ * \tparam T The content ObjectRef type.
+ */
+template <typename T,
+          typename = typename std::enable_if<std::is_base_of<ObjectRef, T>::value>::type>
+class Array : public ObjectRef {
+ public:
+  // constructors
+  /*!
+   * \brief default constructor
+   */
+  Array() { data_ = ArrayNode::make(); }
+
+  /*!
+   * \brief move constructor
+   * \param other source
+   */
+  Array(Array<T>&& other) : ObjectRef() {  // NOLINT(*)
+    data_ = std::move(other.data_);
+  }
+
+  /*!
+   * \brief copy constructor
+   * \param other source
+   */
+  Array(const Array<T>& other) : ObjectRef() {  // NOLINT(*)
+    data_ = other.data_;
+  }
+
+  /*!
+   * \brief constructor from pointer
+   * \param n the container pointer
+   */
+  explicit Array(ObjectPtr<Object> n) : ObjectRef(n) {}
+
+  /*!
+   * \brief constructor from iterator
+   * \param begin begin of iterator
+   * \param end end of iterator
+   * \tparam IterType The type of iterator
+   */
+  template <typename IterType>
+  Array(IterType begin, IterType end) {
+    Assign(begin, end);
+  }
+
+  /*!
+   * \brief constructor from initializer list
+   * \param init The initalizer list

Review comment:
       s/initalizer/initializer

##########
File path: include/tvm/runtime/container.h
##########
@@ -188,6 +188,709 @@ class InplaceArrayBase {
     return data_start + idx * sizeof(ElemType);
   }
 };
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+namespace runtime {
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class IterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit IterAdapter(TIter iter) : iter_(iter) {}
+  inline IterAdapter& operator++() {
+    ++iter_;
+    return *this;
+  }
+  inline IterAdapter& operator--() {
+    --iter_;
+    return *this;
+  }
+  inline IterAdapter& operator++(int) {
+    IterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline IterAdapter& operator--(int) {
+    IterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+
+  inline IterAdapter operator+(difference_type offset) const { return IterAdapter(iter_ + offset); }
+
+  template <typename T = IterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const IterAdapter& rhs) const {
+    return iter_ - rhs.iter_;
+  }
+
+  inline bool operator==(IterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(IterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+/*!
+ * \brief iterator adapter that adapts TIter to return another type.
+ * \tparam Converter a struct that contains converting function
+ * \tparam TIter the content iterator type.
+ */
+template <typename Converter, typename TIter>
+class ReverseIterAdapter {
+ public:
+  using difference_type = typename std::iterator_traits<TIter>::difference_type;
+  using value_type = typename Converter::ResultType;
+  using pointer = typename Converter::ResultType*;
+  using reference = typename Converter::ResultType&;  // NOLINT(*)
+  using iterator_category = typename std::iterator_traits<TIter>::iterator_category;
+
+  explicit ReverseIterAdapter(TIter iter) : iter_(iter) {}
+  inline ReverseIterAdapter& operator++() {
+    --iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator--() {
+    ++iter_;
+    return *this;
+  }
+  inline ReverseIterAdapter& operator++(int) {
+    ReverseIterAdapter copy = *this;
+    --iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter& operator--(int) {
+    ReverseIterAdapter copy = *this;
+    ++iter_;
+    return copy;
+  }
+  inline ReverseIterAdapter operator+(difference_type offset) const {
+    return ReverseIterAdapter(iter_ - offset);
+  }
+
+  template <typename T = ReverseIterAdapter>
+  typename std::enable_if<std::is_same<iterator_category, std::random_access_iterator_tag>::value,
+                          typename T::difference_type>::type inline
+  operator-(const ReverseIterAdapter& rhs) const {
+    return rhs.iter_ - iter_;
+  }
+
+  inline bool operator==(ReverseIterAdapter other) const { return iter_ == other.iter_; }
+  inline bool operator!=(ReverseIterAdapter other) const { return !(*this == other); }
+  inline const value_type operator*() const { return Converter::convert(*iter_); }
+
+ private:
+  TIter iter_;
+};
+
+}  // namespace runtime
+}  // namespace tvm
+
+namespace tvm {
+
+// forward-declare a friend method of ArrayNode.
+TVM_DLL runtime::ObjectRef LoadJSON(std::string json_str);
+
+namespace runtime {
+
+/*! \brief array node content in array */
+class ArrayNode : public Object, public InplaceArrayBase<ArrayNode, ObjectRef> {
+ public:
+  /*! \return The size of the array */
+  inline size_t size() const { return this->size_; }
+
+  /*!
+   * \brief Read i-th element from array.
+   * \param i The index
+   * \return the i-th element.
+   */
+  inline const ObjectRef at(const int64_t i) const { return this->operator[](i); }
+
+  /*! \return begin constant iterator */
+  inline const ObjectRef* begin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end constant iterator */
+  inline const ObjectRef* end() const { return begin() + size_; }
+
+  /*!
+   * \brief Set i-th element of the array in-place
+   * \param i The index
+   * \param item The value to be set
+   */
+  inline void SetItem(const int64_t i, ObjectRef item) { this->operator[](i) = std::move(item); }
+
+  static constexpr const uint32_t _type_index = TypeIndex::kRuntimeArray;
+  static constexpr const char* _type_key = "Array";
+  TVM_DECLARE_FINAL_OBJECT_INFO(ArrayNode, Object);
+
+ private:
+  /*! \return Size of initialized memory, used by InplaceArrayBase. */
+  size_t GetSize() const { return this->size_; }
+
+  /*!
+   * \brief Create an ArrayNode with the given capacity.
+   * \param cap Required capacity
+   * \return Ref-counted ArrayNode requested
+   */
+  static inline ObjectPtr<ArrayNode> make(const int64_t cap = INIT_SIZE) {
+    ObjectPtr<ArrayNode> p = make_inplace_array_object<ArrayNode, ObjectRef>(cap);
+    p->capacity_ = cap;
+    p->size_ = 0;
+    return p;
+  }
+
+  /*! \return begin mutable iterator */
+  inline ObjectRef* MutableBegin() const {
+    return static_cast<ObjectRef*>(InplaceArrayBase::AddressOf(0));
+  }
+
+  /*! \return end mutable iterator */
+  inline ObjectRef* MutableEnd() const { return MutableBegin() + size_; }
+
+  /*! \brief Release reference to all the elements */
+  inline void clear() {
+    for (ObjectRef* itr = MutableEnd(); size_; --size_) {
+      (*--itr).~ObjectRef();
+    }
+  }
+
+  /*! \brief Number of elements used */
+  int64_t size_;
+
+  /*! \brief Number of elements allocated */
+  int64_t capacity_;
+
+  /*! \brief Initial size of ArrayNode */
+  static const constexpr int64_t INIT_SIZE = 16;
+
+  /*! \brief Expansion factor of the Array */
+  static const constexpr int64_t INC_FACTOR = 2;
+
+  // CRTP parent class
+  friend InplaceArrayBase<ArrayNode, ObjectRef>;
+
+  // Reference class
+  template <typename, typename>
+  friend class Array;
+
+  // To specialize make_object<ArrayNode>
+  friend ObjectPtr<ArrayNode> make_object<>();
+
+  // This method requires access to `size_` and `make`
+  friend ObjectRef tvm::LoadJSON(std::string json_str);
+};
+
+/*!
+ * \brief Array container of ObjectRef in DSL graph.
+ *  Array implements copy-on-write semantics, which means array is mutable
+ *  but copy will happen when array is referenced in more than two places.
+ *
+ * operator[] only provide const acces, use Set to mutate the content.
+ * \tparam T The content ObjectRef type.
+ */
+template <typename T,
+          typename = typename std::enable_if<std::is_base_of<ObjectRef, T>::value>::type>
+class Array : public ObjectRef {
+ public:
+  // constructors
+  /*!
+   * \brief default constructor
+   */
+  Array() { data_ = ArrayNode::make(); }
+
+  /*!
+   * \brief move constructor
+   * \param other source
+   */
+  Array(Array<T>&& other) : ObjectRef() {  // NOLINT(*)
+    data_ = std::move(other.data_);
+  }
+
+  /*!
+   * \brief copy constructor
+   * \param other source
+   */
+  Array(const Array<T>& other) : ObjectRef() {  // NOLINT(*)
+    data_ = other.data_;
+  }
+
+  /*!
+   * \brief constructor from pointer
+   * \param n the container pointer
+   */
+  explicit Array(ObjectPtr<Object> n) : ObjectRef(n) {}
+
+  /*!
+   * \brief constructor from iterator
+   * \param begin begin of iterator
+   * \param end end of iterator
+   * \tparam IterType The type of iterator
+   */
+  template <typename IterType>
+  Array(IterType begin, IterType end) {
+    Assign(begin, end);
+  }
+
+  /*!
+   * \brief constructor from initializer list
+   * \param init The initalizer list
+   */
+  Array(std::initializer_list<T> init) {  // NOLINT(*)
+    Assign(init.begin(), init.end());
+  }
+
+  /*!
+   * \brief constructor from vector
+   * \param init The vector
+   */
+  Array(const std::vector<T>& init) {  // NOLINT(*)
+    Assign(init.begin(), init.end());
+  }
+
+  /*!
+   * \brief Constructs a container with n elements. Each element is a copy of val
+   * \param n The size of the container
+   * \param val The init value
+   */
+  explicit Array(const size_t n, const T& val) {
+    ObjectPtr<ArrayNode> p = ArrayNode::make(static_cast<int64_t>(n));
+    for (int64_t& i = p->size_ = 0; i < static_cast<int64_t>(n); ++i) {
+      p->EmplaceInit(i, val);
+    }
+    data_ = std::move(p);
+  }
+
+  /*!
+   * \brief move assign operator
+   * \param other The source of assignment
+   * \return reference to self.
+   */
+  Array<T>& operator=(Array<T>&& other) {
+    data_ = std::move(other.data_);
+    return *this;
+  }
+
+  /*!
+   * \brief copy assign operator
+   * \param other The source of assignment
+   * \return reference to self.
+   */
+  Array<T>& operator=(const Array<T>& other) {
+    data_ = other.data_;
+    return *this;
+  }
+
+ public:
+  // iterators
+  struct ValueConverter {
+    using ResultType = T;
+    static inline T convert(const ObjectRef& n) { return DowncastNoCheck<T>(n); }
+  };
+
+  using iterator = IterAdapter<ValueConverter, const ObjectRef*>;
+  using reverse_iterator = ReverseIterAdapter<ValueConverter, const ObjectRef*>;
+
+  /*! \return begin iterator */
+  inline iterator begin() const { return iterator(GetArrayNode()->begin()); }
+
+  /*! \return end iterator */
+  inline iterator end() const { return iterator(GetArrayNode()->end()); }
+
+  /*! \return rbegin iterator */
+  inline reverse_iterator rbegin() const { return reverse_iterator(GetArrayNode()->end() - 1); }
+
+  /*! \return rend iterator */
+  inline reverse_iterator rend() const { return reverse_iterator(GetArrayNode()->begin() - 1); }
+
+ public:
+  // const methods in std::vector
+  /*!
+   * \brief Immutably read i-th element from array.
+   * \param i The index
+   * \return the i-th element.
+   */
+  inline const T operator[](const int64_t i) const {
+    ArrayNode* data = GetArrayNode();
+    CHECK(data != nullptr) << "ValueError: cannot index a null Array";
+    return DowncastNoCheck<T>((*data)[i]);
+  }
+
+  /*! \return The size of the array */
+  inline size_t size() const {
+    ArrayNode* p = GetArrayNode();
+    return p == nullptr ? 0 : GetArrayNode()->size_;
+  }
+
+  /*! \return The capacity of the array */
+  inline size_t capacity() const {
+    ArrayNode* p = GetArrayNode();
+    return p == nullptr ? 0 : GetArrayNode()->capacity_;
+  }
+
+  /*! \return Whether array is empty */
+  inline bool empty() const { return size() == 0; }
+
+ public:
+  // mutation in std::vector, implements copy-on-write
+
+  /*! \brief Release reference to all the elements */
+  inline void clear() {
+    if (data_ != nullptr) {
+      ArrayNode* p = CopyOnWrite();
+      p->clear();
+    }
+  }
+
+  /*!
+   * \brief Make sure the list has the capacity of at least n
+   * \param n lower bound of the capacity
+   */
+  inline void reserve(const int64_t n) {
+    if (data_ == nullptr || n > GetArrayNode()->capacity_) {
+      SwitchContainer(n);
+    }
+    CHECK_GE(GetArrayNode()->capacity_, n);
+  }
+
+  /*!
+   * \brief Resize the array.
+   * \param n The new size.
+   */
+  inline void resize(const int64_t n) {

Review comment:
       no need to have `const`




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org