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].
20struct 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].
65struct 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.
91namespace 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].
260template<typename T>
261class BLArray : public BLArrayCore {
262public:
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