|
36 | 36 | namespace tvm { |
37 | 37 | namespace ffi { |
38 | 38 | namespace details { |
39 | | -/*! |
40 | | - * \brief Base template for classes with array like memory layout. |
41 | | - * |
42 | | - * It provides general methods to access the memory. The memory |
43 | | - * layout is ArrayType + [ElemType]. The alignment of ArrayType |
44 | | - * and ElemType is handled by the memory allocator. |
45 | | - * |
46 | | - * \tparam ArrayType The array header type, contains object specific metadata. |
47 | | - * \tparam ElemType The type of objects stored in the array right after |
48 | | - * ArrayType. |
49 | | - * |
50 | | - * \code{.cpp} |
51 | | - * // Example usage of the template to define a simple array wrapper |
52 | | - * class ArrayObj : public tvm::ffi::details::InplaceArrayBase<ArrayObj, Elem> { |
53 | | - * public: |
54 | | - * // Wrap EmplaceInit to initialize the elements |
55 | | - * template <typename Iterator> |
56 | | - * void Init(Iterator begin, Iterator end) { |
57 | | - * size_t num_elems = std::distance(begin, end); |
58 | | - * auto it = begin; |
59 | | - * this->size = 0; |
60 | | - * for (size_t i = 0; i < num_elems; ++i) { |
61 | | - * InplaceArrayBase::EmplaceInit(i, *it++); |
62 | | - * this->size++; |
63 | | - * } |
64 | | - * } |
65 | | - * } |
66 | | - * |
67 | | - * void test_function() { |
68 | | - * vector<Elem> fields; |
69 | | - * auto ptr = make_inplace_array_object<ArrayObj, Elem>(fields.size()); |
70 | | - * ptr->Init(fields.begin(), fields.end()); |
71 | | - * |
72 | | - * // Access the 0th element in the array. |
73 | | - * assert(ptr->operator[](0) == fields[0]); |
74 | | - * } |
75 | | - * \endcode |
76 | | - */ |
77 | | -template <typename ArrayType, typename ElemType> |
78 | | -class InplaceArrayBase { |
79 | | - public: |
80 | | - /*! |
81 | | - * \brief Access element at index |
82 | | - * \param idx The index of the element. |
83 | | - * \return Const reference to ElemType at the index. |
84 | | - */ |
85 | | - const ElemType& operator[](size_t idx) const { |
86 | | - size_t size = Self()->GetSize(); |
87 | | - if (idx > size) { |
88 | | - TVM_FFI_THROW(IndexError) << "Index " << idx << " out of bounds " << size; |
89 | | - } |
90 | | - return *(reinterpret_cast<ElemType*>(AddressOf(idx))); |
91 | | - } |
92 | | - |
93 | | - /*! |
94 | | - * \brief Access element at index |
95 | | - * \param idx The index of the element. |
96 | | - * \return Reference to ElemType at the index. |
97 | | - */ |
98 | | - ElemType& operator[](size_t idx) { |
99 | | - size_t size = Self()->GetSize(); |
100 | | - if (idx > size) { |
101 | | - TVM_FFI_THROW(IndexError) << "Index " << idx << " out of bounds " << size; |
102 | | - } |
103 | | - return *(reinterpret_cast<ElemType*>(AddressOf(idx))); |
104 | | - } |
105 | | - |
106 | | - /*! |
107 | | - * \brief Destroy the Inplace Array Base object |
108 | | - */ |
109 | | - ~InplaceArrayBase() { |
110 | | - if constexpr (!(std::is_standard_layout_v<ElemType> && std::is_trivial_v<ElemType>)) { |
111 | | - size_t size = Self()->GetSize(); |
112 | | - for (size_t i = 0; i < size; ++i) { |
113 | | - ElemType* fp = reinterpret_cast<ElemType*>(AddressOf(i)); |
114 | | - fp->ElemType::~ElemType(); |
115 | | - } |
116 | | - } |
117 | | - } |
118 | | - |
119 | | - private: |
120 | | - InplaceArrayBase() = default; |
121 | | - friend ArrayType; |
122 | | - |
123 | | - protected: |
124 | | - /*! |
125 | | - * \brief Construct a value in place with the arguments. |
126 | | - * |
127 | | - * \tparam Args Type parameters of the arguments. |
128 | | - * \param idx Index of the element. |
129 | | - * \param args Arguments to construct the new value. |
130 | | - * |
131 | | - * \note Please make sure ArrayType::GetSize returns 0 before first call of |
132 | | - * EmplaceInit, and increment GetSize by 1 each time EmplaceInit succeeds. |
133 | | - */ |
134 | | - template <typename... Args> |
135 | | - void EmplaceInit(size_t idx, Args&&... args) { |
136 | | - void* field_ptr = AddressOf(idx); |
137 | | - new (field_ptr) ElemType(std::forward<Args>(args)...); |
138 | | - } |
139 | | - |
140 | | - /*! |
141 | | - * \brief Return the self object for the array. |
142 | | - * |
143 | | - * \return Pointer to ArrayType. |
144 | | - */ |
145 | | - inline ArrayType* Self() const { |
146 | | - return static_cast<ArrayType*>(const_cast<InplaceArrayBase*>(this)); |
147 | | - } |
148 | | - |
149 | | - /*! |
150 | | - * \brief Return the raw pointer to the element at idx. |
151 | | - * |
152 | | - * \param idx The index of the element. |
153 | | - * \return Raw pointer to the element. |
154 | | - */ |
155 | | - void* AddressOf(size_t idx) const { |
156 | | - static_assert( |
157 | | - alignof(ArrayType) % alignof(ElemType) == 0 && sizeof(ArrayType) % alignof(ElemType) == 0, |
158 | | - "The size and alignment of ArrayType should respect " |
159 | | - "ElemType's alignment."); |
160 | | - |
161 | | - size_t kDataStart = sizeof(ArrayType); |
162 | | - ArrayType* self = Self(); |
163 | | - char* data_start = reinterpret_cast<char*>(self) + kDataStart; |
164 | | - return data_start + idx * sizeof(ElemType); |
165 | | - } |
166 | | -}; |
167 | 39 |
|
168 | 40 | /*! |
169 | 41 | * \brief iterator adapter that adapts TIter to return another type. |
|
0 commit comments