1 | // [Blend2D] |
2 | // 2D Vector Graphics Powered by a JIT Compiler. |
3 | // |
4 | // [License] |
5 | // Zlib - See LICENSE.md file in the package. |
6 | |
7 | #ifndef BLEND2D_BLARRAY_H |
8 | #define BLEND2D_BLARRAY_H |
9 | |
10 | #include "./blvariant.h" |
11 | |
12 | // ============================================================================ |
13 | // [BLArray - Core] |
14 | // ============================================================================ |
15 | |
16 | //! \addtogroup blend2d_api_globals |
17 | //! \{ |
18 | |
19 | //! Array container [C Interface - Impl]. |
20 | struct BLArrayImpl { |
21 | union { |
22 | struct { |
23 | //! Array data (as `void`). |
24 | void* data; |
25 | //! Array size. |
26 | size_t size; |
27 | }; |
28 | //! Array data and size as a view. |
29 | BLDataView view; |
30 | }; |
31 | //! Array capacity. |
32 | size_t capacity; |
33 | |
34 | //! Reference count. |
35 | volatile size_t refCount; |
36 | //! Impl type. |
37 | uint8_t implType; |
38 | //! Impl traits. |
39 | uint8_t implTraits; |
40 | //! Memory pool data. |
41 | uint16_t memPoolData; |
42 | |
43 | //! Item size in bytes. |
44 | uint8_t itemSize; |
45 | //! Function dispatch used to handle arrays that don't store simple items. |
46 | uint8_t dispatchType; |
47 | //! Reserved, must be set to 0. |
48 | uint8_t reserved[2]; |
49 | |
50 | // -------------------------------------------------------------------------- |
51 | #ifdef __cplusplus |
52 | |
53 | //! Returns the pointer to the `data` casted to `T*`. |
54 | template<typename T> |
55 | BL_INLINE T* dataAs() noexcept { return (T*)data; } |
56 | //! Returns the pointer to the `data` casted to `const T*`. |
57 | template<typename T> |
58 | BL_INLINE const T* dataAs() const noexcept { return (const T*)data; } |
59 | |
60 | #endif |
61 | // -------------------------------------------------------------------------- |
62 | }; |
63 | |
64 | //! Array container [C Interface - Core]. |
65 | struct BLArrayCore { |
66 | BLArrayImpl* impl; |
67 | |
68 | // -------------------------------------------------------------------------- |
69 | #ifdef __cplusplus |
70 | |
71 | template<typename T> |
72 | BL_INLINE T& dcast() noexcept { return reinterpret_cast<T&>(*this); } |
73 | template<typename T> |
74 | BL_INLINE const T& dcast() const noexcept { return reinterpret_cast<const T&>(*this); } |
75 | |
76 | #endif |
77 | // -------------------------------------------------------------------------- |
78 | }; |
79 | |
80 | //! \} |
81 | |
82 | // ============================================================================ |
83 | // [BLArray - Internal] |
84 | // ============================================================================ |
85 | |
86 | //! \cond INTERNAL |
87 | #ifdef __cplusplus |
88 | //! \ingroup blend2d_internal |
89 | //! |
90 | //! Internals behind BLArray<T> implementation. |
91 | namespace BLArrayInternal { |
92 | // These are required to properly use the C API from C++ BLArray<T>. Category |
93 | // provides a rough overview of `BLArray<T>` type category (like int, float) |
94 | // and the other APIs provide some basic traits that the implementation needs. |
95 | |
96 | enum TypeCategory { |
97 | TYPE_CATEGORY_UNKNOWN = 0, |
98 | TYPE_CATEGORY_VAR = 1, |
99 | TYPE_CATEGORY_PTR = 2, |
100 | TYPE_CATEGORY_INT = 3, |
101 | TYPE_CATEGORY_FP = 4, |
102 | TYPE_CATEGORY_STRUCT = 5 |
103 | }; |
104 | |
105 | template<typename T> |
106 | struct TypeCategoryOf { |
107 | enum { |
108 | kValue = std::is_pointer<T>::value ? TYPE_CATEGORY_PTR : |
109 | std::is_integral<T>::value ? TYPE_CATEGORY_INT : |
110 | std::is_floating_point<T>::value ? TYPE_CATEGORY_FP : TYPE_CATEGORY_STRUCT |
111 | }; |
112 | }; |
113 | |
114 | template<> struct TypeCategoryOf<BLVariant > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
115 | template<> struct TypeCategoryOf<BLString > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
116 | template<> struct TypeCategoryOf<BLPath > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
117 | template<> struct TypeCategoryOf<BLRegion > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
118 | template<> struct TypeCategoryOf<BLImage > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
119 | template<> struct TypeCategoryOf<BLImageCodec > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
120 | template<> struct TypeCategoryOf<BLImageDecoder> { enum { kValue = TYPE_CATEGORY_VAR }; }; |
121 | template<> struct TypeCategoryOf<BLImageEncoder> { enum { kValue = TYPE_CATEGORY_VAR }; }; |
122 | template<> struct TypeCategoryOf<BLPattern > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
123 | template<> struct TypeCategoryOf<BLGradient > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
124 | template<> struct TypeCategoryOf<BLContext > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
125 | template<> struct TypeCategoryOf<BLGlyphBuffer > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
126 | template<> struct TypeCategoryOf<BLFont > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
127 | template<> struct TypeCategoryOf<BLFontFace > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
128 | template<> struct TypeCategoryOf<BLFontData > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
129 | template<> struct TypeCategoryOf<BLFontLoader > { enum { kValue = TYPE_CATEGORY_VAR }; }; |
130 | |
131 | template<typename T, int TypeCategory> |
132 | struct ArrayTraitsByCategory { |
133 | static constexpr const uint32_t kImplType = BL_IMPL_TYPE_NULL; |
134 | |
135 | typedef T CompatibleType; |
136 | static BL_INLINE const T& pass(const T& arg) noexcept { return arg; } |
137 | }; |
138 | |
139 | template<typename T> |
140 | struct ArrayTraitsByCategory<T, TYPE_CATEGORY_VAR> { |
141 | static constexpr const uint32_t kImplType = BL_IMPL_TYPE_ARRAY_VAR; |
142 | |
143 | typedef T CompatibleType; |
144 | static BL_INLINE const CompatibleType& pass(const T& arg) noexcept { return arg; } |
145 | }; |
146 | |
147 | template<typename T> |
148 | struct ArrayTraitsByCategory<T, TYPE_CATEGORY_PTR> { |
149 | static constexpr const uint32_t kImplType = |
150 | sizeof(T) == 4 ? BL_IMPL_TYPE_ARRAY_U32 : BL_IMPL_TYPE_ARRAY_U64; |
151 | |
152 | typedef typename BLInternal::StdInt<sizeof(T), 1>::Type CompatibleType; |
153 | static BL_INLINE CompatibleType pass(const T& arg) noexcept { return (CompatibleType)arg; } |
154 | }; |
155 | |
156 | template<typename T> |
157 | struct ArrayTraitsByCategory<T, TYPE_CATEGORY_INT> { |
158 | static constexpr const uint32_t kImplType = |
159 | sizeof(T) == 1 && std::is_signed <T>::value ? BL_IMPL_TYPE_ARRAY_I8 : |
160 | sizeof(T) == 1 && std::is_unsigned<T>::value ? BL_IMPL_TYPE_ARRAY_U8 : |
161 | sizeof(T) == 2 && std::is_signed <T>::value ? BL_IMPL_TYPE_ARRAY_I16 : |
162 | sizeof(T) == 2 && std::is_unsigned<T>::value ? BL_IMPL_TYPE_ARRAY_U16 : |
163 | sizeof(T) == 4 && std::is_signed <T>::value ? BL_IMPL_TYPE_ARRAY_I32 : |
164 | sizeof(T) == 4 && std::is_unsigned<T>::value ? BL_IMPL_TYPE_ARRAY_U32 : |
165 | sizeof(T) == 8 && std::is_signed <T>::value ? BL_IMPL_TYPE_ARRAY_I64 : |
166 | sizeof(T) == 8 && std::is_unsigned<T>::value ? BL_IMPL_TYPE_ARRAY_U64 : BL_IMPL_TYPE_NULL; |
167 | |
168 | typedef typename BLInternal::StdInt<sizeof(T), 1>::Type CompatibleType; |
169 | static BL_INLINE CompatibleType pass(const T& arg) noexcept { return (CompatibleType)arg; } |
170 | }; |
171 | |
172 | template<typename T> |
173 | struct ArrayTraitsByCategory<T, TYPE_CATEGORY_FP> { |
174 | static constexpr const uint32_t kImplType = |
175 | sizeof(T) == 4 ? BL_IMPL_TYPE_ARRAY_F32 : |
176 | sizeof(T) == 8 ? BL_IMPL_TYPE_ARRAY_F64 : BL_IMPL_TYPE_NULL; |
177 | |
178 | typedef T CompatibleType; |
179 | static BL_INLINE CompatibleType pass(const T& arg) noexcept { return (CompatibleType)arg; } |
180 | }; |
181 | |
182 | template<typename T> |
183 | struct ArrayTraitsByCategory<T, TYPE_CATEGORY_STRUCT> { |
184 | static constexpr const uint32_t kImplType = |
185 | sizeof(T) == 1 ? BL_IMPL_TYPE_ARRAY_STRUCT_1 : |
186 | sizeof(T) == 2 ? BL_IMPL_TYPE_ARRAY_STRUCT_2 : |
187 | sizeof(T) == 3 ? BL_IMPL_TYPE_ARRAY_STRUCT_3 : |
188 | sizeof(T) == 4 ? BL_IMPL_TYPE_ARRAY_STRUCT_4 : |
189 | sizeof(T) == 6 ? BL_IMPL_TYPE_ARRAY_STRUCT_6 : |
190 | sizeof(T) == 8 ? BL_IMPL_TYPE_ARRAY_STRUCT_8 : |
191 | sizeof(T) == 10 ? BL_IMPL_TYPE_ARRAY_STRUCT_10 : |
192 | sizeof(T) == 12 ? BL_IMPL_TYPE_ARRAY_STRUCT_12 : |
193 | sizeof(T) == 16 ? BL_IMPL_TYPE_ARRAY_STRUCT_16 : |
194 | sizeof(T) == 20 ? BL_IMPL_TYPE_ARRAY_STRUCT_20 : |
195 | sizeof(T) == 24 ? BL_IMPL_TYPE_ARRAY_STRUCT_24 : |
196 | sizeof(T) == 32 ? BL_IMPL_TYPE_ARRAY_STRUCT_32 : BL_IMPL_TYPE_NULL; |
197 | |
198 | typedef T CompatibleType; |
199 | static BL_INLINE CompatibleType pass(const T& arg) noexcept { return (CompatibleType)arg; } |
200 | }; |
201 | |
202 | template<typename T> |
203 | struct ArrayTraits : public ArrayTraitsByCategory<T, TypeCategoryOf<T>::kValue> {}; |
204 | |
205 | template<typename T> |
206 | BL_INLINE const T& first(const T& arg) noexcept { return arg; } |
207 | template<typename T, typename... Args> |
208 | BL_INLINE const T& first(const T& arg, Args&&...) noexcept { return arg; } |
209 | |
210 | template<typename T, typename Arg0> |
211 | BL_INLINE void copyToUninitialized(T* dst, Arg0&& src) noexcept { |
212 | // Otherwise MSVC would emit null checks... |
213 | BL_ASSUME(dst != nullptr); |
214 | new(BLInternal::PlacementNew { dst }) T(std::forward<Arg0>(src)); |
215 | } |
216 | |
217 | template<typename T, typename Arg0, typename... Args> |
218 | BL_INLINE void copyToUninitialized(T* dst, Arg0&& arg0, Args&&... args) noexcept { |
219 | copyToUninitialized(dst + 0, std::forward<Arg0>(arg0)); |
220 | copyToUninitialized(dst + 1, std::forward<Args>(args)...); |
221 | } |
222 | |
223 | template<typename T> BL_INLINE BLResult appendItem(BLArrayCore* self, const T& item) noexcept { return blArrayAppendItem(self, &item); } |
224 | template<> BL_INLINE BLResult appendItem(BLArrayCore* self, const uint8_t& item) noexcept { return blArrayAppendU8(self, item); } |
225 | template<> BL_INLINE BLResult appendItem(BLArrayCore* self, const uint16_t& item) noexcept { return blArrayAppendU16(self, item); } |
226 | template<> BL_INLINE BLResult appendItem(BLArrayCore* self, const uint32_t& item) noexcept { return blArrayAppendU32(self, item); } |
227 | template<> BL_INLINE BLResult appendItem(BLArrayCore* self, const uint64_t& item) noexcept { return blArrayAppendU64(self, item); } |
228 | template<> BL_INLINE BLResult appendItem(BLArrayCore* self, const float& item) noexcept { return blArrayAppendF32(self, item); } |
229 | template<> BL_INLINE BLResult appendItem(BLArrayCore* self, const double& item) noexcept { return blArrayAppendF64(self, item); } |
230 | |
231 | template<typename T> BL_INLINE BLResult insertItem(BLArrayCore* self, size_t index, const T& item) noexcept { return blArrayInsertItem(self, index, &item); } |
232 | template<> BL_INLINE BLResult insertItem(BLArrayCore* self, size_t index, const uint8_t& item) noexcept { return blArrayInsertU8(self, index, item); } |
233 | template<> BL_INLINE BLResult insertItem(BLArrayCore* self, size_t index, const uint16_t& item) noexcept { return blArrayInsertU16(self, index, item); } |
234 | template<> BL_INLINE BLResult insertItem(BLArrayCore* self, size_t index, const uint32_t& item) noexcept { return blArrayInsertU32(self, index, item); } |
235 | template<> BL_INLINE BLResult insertItem(BLArrayCore* self, size_t index, const uint64_t& item) noexcept { return blArrayInsertU64(self, index, item); } |
236 | template<> BL_INLINE BLResult insertItem(BLArrayCore* self, size_t index, const float& item) noexcept { return blArrayInsertF32(self, index, item); } |
237 | template<> BL_INLINE BLResult insertItem(BLArrayCore* self, size_t index, const double& item) noexcept { return blArrayInsertF64(self, index, item); } |
238 | |
239 | template<typename T> BL_INLINE BLResult replaceItem(BLArrayCore* self, size_t index, const T& item) noexcept { return blArrayReplaceItem(self, index, &item); } |
240 | template<> BL_INLINE BLResult replaceItem(BLArrayCore* self, size_t index, const uint8_t& item) noexcept { return blArrayReplaceU8(self, index, item); } |
241 | template<> BL_INLINE BLResult replaceItem(BLArrayCore* self, size_t index, const uint16_t& item) noexcept { return blArrayReplaceU16(self, index, item); } |
242 | template<> BL_INLINE BLResult replaceItem(BLArrayCore* self, size_t index, const uint32_t& item) noexcept { return blArrayReplaceU32(self, index, item); } |
243 | template<> BL_INLINE BLResult replaceItem(BLArrayCore* self, size_t index, const uint64_t& item) noexcept { return blArrayReplaceU64(self, index, item); } |
244 | template<> BL_INLINE BLResult replaceItem(BLArrayCore* self, size_t index, const float& item) noexcept { return blArrayReplaceF32(self, index, item); } |
245 | template<> BL_INLINE BLResult replaceItem(BLArrayCore* self, size_t index, const double& item) noexcept { return blArrayReplaceF64(self, index, item); } |
246 | } // {BLArrayInternal} |
247 | |
248 | #endif |
249 | //! \endcond |
250 | |
251 | // ============================================================================ |
252 | // [BLArray - C++] |
253 | // ============================================================================ |
254 | |
255 | //! \addtogroup blend2d_api_globals |
256 | //! \{ |
257 | |
258 | #ifdef __cplusplus |
259 | //! Array container (template) [C++ API]. |
260 | template<typename T> |
261 | class BLArray : public BLArrayCore { |
262 | public: |
263 | //! \cond INTERNAL |
264 | //! Array traits of `T`. |
265 | typedef BLArrayInternal::ArrayTraits<T> Traits; |
266 | |
267 | //! Implementation type of this BLArray<T> matching `T` traits. |
268 | static constexpr const uint32_t kImplType = Traits::kImplType; |
269 | |
270 | static_assert(uint32_t(kImplType) != BL_IMPL_TYPE_NULL, |
271 | "Type 'T' cannot be used with 'BLArray<T>' as it's either non-trivial or non-specialized" ); |
272 | //! \endcond |
273 | |
274 | //! \name Construction & Destruction |
275 | //! \{ |
276 | |
277 | //! Creates a default constructed array. |
278 | //! |
279 | //! Default constructed arrays share the default "none" instance. |
280 | BL_INLINE BLArray() noexcept { this->impl = none().impl; } |
281 | BL_INLINE BLArray(BLArray&& other) noexcept { blVariantInitMove(this, &other); } |
282 | BL_INLINE BLArray(const BLArray& other) noexcept { blVariantInitWeak(this, &other); } |
283 | BL_INLINE explicit BLArray(BLArrayImpl* impl) noexcept { this->impl = impl; } |
284 | |
285 | //! Destroys the array. |
286 | BL_INLINE ~BLArray() noexcept { blArrayReset(this); } |
287 | |
288 | //! \} |
289 | |
290 | //! \name Overloaded Operators |
291 | //! \{ |
292 | |
293 | //! Returns `true` whether the array's length is `1` or greater. |
294 | BL_INLINE explicit operator bool() const noexcept { return !empty(); } |
295 | |
296 | BL_INLINE BLArray& operator=(BLArray&& other) noexcept { blArrayAssignMove(this, &other); return *this; } |
297 | BL_INLINE BLArray& operator=(const BLArray& other) noexcept { blArrayAssignWeak(this, &other); return *this; } |
298 | |
299 | BL_INLINE bool operator==(const BLArray& other) noexcept { return equals(other); } |
300 | BL_INLINE bool operator!=(const BLArray& other) noexcept { return !equals(other); } |
301 | |
302 | BL_INLINE const T& operator[](size_t index) const noexcept { return at(index); } |
303 | |
304 | //! \} |
305 | |
306 | //! \name Common Functionality |
307 | //! \{ |
308 | |
309 | //! Resets the array into a default constructed state by clearing its content |
310 | //! and releasing its memory. |
311 | BL_INLINE BLResult reset() noexcept { return blArrayReset(this); } |
312 | BL_INLINE void swap(BLArray<T>& other) noexcept { std::swap(this->impl, other.impl); } |
313 | |
314 | BL_INLINE BLResult assign(BLArray<T>&& other) noexcept { return blArrayAssignMove(this, &other); } |
315 | BL_INLINE BLResult assign(const BLArray<T>& other) noexcept { return blArrayAssignWeak(this, &other); } |
316 | BL_INLINE BLResult assignDeep(const BLArray<T>& other) noexcept { return blArrayAssignDeep(this, &other); } |
317 | |
318 | template<typename... Args> |
319 | BL_INLINE BLResult assign_v(Args&&... args) noexcept { return modify_v(BL_MODIFY_OP_ASSIGN_FIT, std::forward<Args>(args)...); } |
320 | |
321 | BL_INLINE BLResult assignView(const BLArrayView<T>& view) noexcept { return blArrayAssignView(this, (const void*)view.data, view.size); } |
322 | BL_INLINE BLResult assignView(const T* items, size_t n) noexcept { return blArrayAssignView(this, (const void*)items, n); } |
323 | |
324 | //! Tests whether the array is a built-in null instance. |
325 | BL_INLINE bool isNone() const noexcept { return (impl->implTraits & BL_IMPL_TRAIT_NULL) != 0; } |
326 | //! Tests whether the array is empty. |
327 | BL_INLINE bool empty() const noexcept { return impl->size == 0; } |
328 | |
329 | //! Returnsn whether the content of this array and `other` matches. |
330 | BL_INLINE bool equals(const BLArray<T>& other) const noexcept { return blArrayEquals(this, &other); } |
331 | |
332 | //! \} |
333 | |
334 | //! \name Create Functionality |
335 | //! \{ |
336 | |
337 | //! Create array that uses an external `data` buffer. |
338 | //! |
339 | //! \param data External data buffer to use (cannot be NULL). |
340 | //! \param size Size of the data buffer in items. |
341 | //! \param capacity Capacity of the buffer, cannot be zero or smaller than `size`. |
342 | //! \param dataAccessFlags Flags that describe whether the data is read-only or read-write, see `BLDataAccessFlags`. |
343 | //! \param destroyFunc A function that would be called when the array is destroyed (can be null if you don't need it). |
344 | //! \param destroyData Data passed to `destroyFunc`. |
345 | //! |
346 | //! \note The old content of the array is destroyed and replaced with an Impl |
347 | //! that uses the external data passed. |
348 | BL_INLINE BLResult createFromData(T* data, size_t size, size_t capacity, uint32_t dataAccessFlags, BLDestroyImplFunc destroyFunc = nullptr, void* destroyData = nullptr) noexcept { |
349 | return blArrayCreateFromData(this, data, size, capacity, dataAccessFlags, destroyFunc, destroyData); |
350 | } |
351 | |
352 | //! \} |
353 | |
354 | //! \name Array Storage |
355 | //! \{ |
356 | |
357 | //! Returns the size of the array (number of elements). |
358 | BL_INLINE size_t size() const noexcept { return impl->size; } |
359 | //! Returns the capacity of the array (number of elements). |
360 | BL_INLINE size_t capacity() const noexcept { return impl->capacity; } |
361 | |
362 | //! Returns a pointer to the array data. |
363 | BL_INLINE const T* data() const noexcept { return static_cast<const T*>(impl->data); } |
364 | //! Returns a pointer to the end of array data. |
365 | BL_INLINE const T* end() const noexcept { return static_cast<const T*>(impl->data) + impl->size; } |
366 | |
367 | //! Returns the array data as `BLArrayView<T>`. |
368 | BL_INLINE const BLArrayView<T>& view() const noexcept { |
369 | BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_STRICT_ALIASING) |
370 | return reinterpret_cast<const BLArrayView<T>&>(impl->view); |
371 | BL_DIAGNOSTIC_POP |
372 | } |
373 | |
374 | BL_INLINE const T& at(size_t index) const noexcept { |
375 | BL_ASSERT(index < impl->size); |
376 | return data()[index]; |
377 | } |
378 | |
379 | BL_INLINE const T& first() const noexcept { return at(0); } |
380 | BL_INLINE const T& last() const noexcept { return at(impl->size - 1); } |
381 | |
382 | BL_INLINE BLResult clear() noexcept { return blArrayClear(this); } |
383 | BL_INLINE BLResult shrink() noexcept { return blArrayShrink(this); } |
384 | BL_INLINE BLResult reserve(size_t n) noexcept { return blArrayReserve(this, n); } |
385 | |
386 | BL_INLINE BLResult truncate(size_t n) noexcept { return blArrayResize(this, blMin(n, impl->size), nullptr); } |
387 | BL_INLINE BLResult resize(size_t n, const T& fill) noexcept { return blArrayResize(this, n, &fill); } |
388 | |
389 | //! \} |
390 | |
391 | //! \name Array Manipulation |
392 | //! \{ |
393 | |
394 | BL_INLINE BLResult makeMutable(T** dataOut) noexcept { return blArrayMakeMutable(this, (void**)dataOut); } |
395 | BL_INLINE BLResult modifyOp(uint32_t op, size_t n, T** dataOut) noexcept { return blArrayModifyOp(this, op, n, (void**)dataOut); } |
396 | BL_INLINE BLResult insertOp(size_t index, size_t n, T** dataOut) noexcept { return blArrayInsertOp(this, index, n, (void**)dataOut); } |
397 | |
398 | template<typename... Args> |
399 | BL_INLINE BLResult modify_v(uint32_t op, Args&&... args) noexcept { |
400 | T* dst; |
401 | BL_PROPAGATE(blArrayModifyOp(this, op, sizeof...(args), (void**)&dst)); |
402 | BLArrayInternal::copyToUninitialized(dst, std::forward<Args>(args)...); |
403 | return BL_SUCCESS; |
404 | } |
405 | |
406 | template<typename... Args> |
407 | BL_INLINE BLResult append(Args&&... args) noexcept { |
408 | if (sizeof...(args) == 1) |
409 | return BLArrayInternal::appendItem(this, Traits::pass(BLArrayInternal::first(std::forward<Args>(args)...))); |
410 | else |
411 | return modify_v(BL_MODIFY_OP_APPEND_GROW, std::forward<Args>(args)...); |
412 | } |
413 | |
414 | BL_INLINE BLResult appendView(const BLArrayView<T>& view) noexcept { return blArrayAppendView(this, (const void*)view.data, view.size); } |
415 | BL_INLINE BLResult appendView(const T* items, size_t n) noexcept { return blArrayAppendView(this, (const void*)items, n); } |
416 | |
417 | template<typename... Args> |
418 | BL_INLINE BLResult prepend(Args&&... args) noexcept { |
419 | if (sizeof...(args) == 1) |
420 | return BLArrayInternal::insertItem(this, 0, Traits::pass(BLArrayInternal::first(std::forward<Args>(args)...))); |
421 | else |
422 | return insert(0, std::forward<Args>(args)...); |
423 | } |
424 | |
425 | BL_INLINE BLResult prependView(const BLArrayView<T>& view) noexcept { return blArrayInsertView(this, 0, (const void*)view.data, view.size); } |
426 | BL_INLINE BLResult prependView(const T* items, size_t n) noexcept { return blArrayInsertView(this, 0, (const void*)items, n); } |
427 | |
428 | template<typename... Args> |
429 | BL_INLINE BLResult insert(size_t index, Args&&... args) noexcept { |
430 | if (sizeof...(args) == 1) { |
431 | return BLArrayInternal::insertItem(this, index, Traits::pass(BLArrayInternal::first(std::forward<Args>(args)...))); |
432 | } |
433 | else { |
434 | T* dst; |
435 | BL_PROPAGATE(blArrayInsertOp(this, index, sizeof...(args), (void**)&dst)); |
436 | BLArrayInternal::copyToUninitialized(dst, std::forward<Args>(args)...); |
437 | return BL_SUCCESS; |
438 | } |
439 | } |
440 | |
441 | BL_INLINE BLResult insertView(size_t index, const BLArrayView<T>& view) noexcept { return blArrayInsertView(this, index, (const void*)view.data, view.size); } |
442 | BL_INLINE BLResult insertView(size_t index, const T* items, size_t n) noexcept { return blArrayInsertView(this, index, (const void*)items, n); } |
443 | |
444 | BL_INLINE BLResult replace(size_t index, const T& item) noexcept { return BLArrayInternal::replaceItem(this, index, Traits::pass(item)); } |
445 | |
446 | BL_INLINE BLResult replaceView(const BLRange& range, BLArrayView<T>& view) noexcept { return blArrayReplaceView(this, range.start, range.end, (const void*)view.data, view.size); } |
447 | BL_INLINE BLResult replaceView(const BLRange& range, const T* items, size_t n) noexcept { return blArrayReplaceView(this, range.start, range.end, items, n); } |
448 | |
449 | //! Removes an item at the given `index`. |
450 | BL_INLINE BLResult remove(size_t index) noexcept { return blArrayRemoveIndex(this, index); } |
451 | //! Removes items at the given `range`. |
452 | BL_INLINE BLResult remove(const BLRange& range) noexcept { return blArrayRemoveRange(this, range.start, range.end); } |
453 | |
454 | //! \} |
455 | |
456 | //! \name Search |
457 | //! \{ |
458 | |
459 | //! Returns the first index at which a given `item` can be found in the |
460 | //! array, or `SIZE_MAX` if not present. |
461 | BL_INLINE size_t indexOf(const T& item) const noexcept { |
462 | return indexOf(item, 0); |
463 | } |
464 | |
465 | //! Returns the index at which a given `item` can be found in the array |
466 | //! starting from `fromIndex`, or `SIZE_MAX` if not present. |
467 | BL_INLINE size_t indexOf(const T& item, size_t fromIndex) const noexcept { |
468 | const T* p = data(); |
469 | size_t iEnd = size(); |
470 | |
471 | for (size_t i = fromIndex; i < iEnd; i++) |
472 | if (p[i] == item) |
473 | return i; |
474 | |
475 | return SIZE_MAX; |
476 | } |
477 | |
478 | //! Returns the last index at which a given `item` can be found in the array, |
479 | //! or `SIZE_MAX` if not present. |
480 | BL_INLINE size_t lastIndexOf(const T& item) const noexcept { |
481 | const T* p = data(); |
482 | size_t i = size(); |
483 | |
484 | while (--i != SIZE_MAX && !(p[i] == item)) |
485 | continue; |
486 | |
487 | return i; |
488 | } |
489 | |
490 | //! Returns the index at which a given `item` can be found in the array |
491 | //! starting from `fromIndex` and ending at `0`, or `SIZE_MAX` if not present. |
492 | BL_INLINE size_t lastIndexOf(const T& item, size_t fromIndex) const noexcept { |
493 | const T* p = data(); |
494 | size_t i = size() - 1; |
495 | |
496 | if (i == SIZE_MAX) |
497 | return i; |
498 | |
499 | i = blMin<size_t>(i, fromIndex); |
500 | while (!(p[i] == item) && --i != SIZE_MAX) |
501 | continue; |
502 | |
503 | return i; |
504 | } |
505 | |
506 | //! \} |
507 | |
508 | static BL_INLINE const BLArray<T>& none() noexcept { return reinterpret_cast<const BLArray<T>*>(blNone)[kImplType]; } |
509 | }; |
510 | #endif |
511 | |
512 | //! \} |
513 | |
514 | #endif // BLEND2D_BLARRAY_H |
515 | |