OpenShot Audio Library | OpenShotAudio 0.4.0
 
Loading...
Searching...
No Matches
juce_ArrayBase.h
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
39template <class ElementType, class TypeOfCriticalSectionToUse>
40class ArrayBase : public TypeOfCriticalSectionToUse
41{
42private:
43 using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
44
45 template <class OtherElementType, class OtherCriticalSection>
46 using AllowConversion = std::enable_if_t<! std::is_same_v<std::tuple<ElementType, TypeOfCriticalSectionToUse>,
47 std::tuple<OtherElementType, OtherCriticalSection>>>;
48
49public:
50 //==============================================================================
51 ArrayBase() = default;
52
53 ~ArrayBase()
54 {
55 clear();
56 }
57
58 ArrayBase (ArrayBase&& other) noexcept
59 : elements (std::move (other.elements)),
60 numAllocated (other.numAllocated),
61 numUsed (other.numUsed)
62 {
63 other.numAllocated = 0;
64 other.numUsed = 0;
65 }
66
67 ArrayBase& operator= (ArrayBase&& other) noexcept
68 {
69 if (this != &other)
70 {
71 auto tmp (std::move (other));
72 swapWith (tmp);
73 }
74
75 return *this;
76 }
77
83 template <class OtherElementType,
84 class OtherCriticalSection,
85 typename = AllowConversion<OtherElementType, OtherCriticalSection>>
86 ArrayBase (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
87 : elements (std::move (other.elements)),
88 numAllocated (other.numAllocated),
89 numUsed (other.numUsed)
90 {
91 other.numAllocated = 0;
92 other.numUsed = 0;
93 }
94
100 template <class OtherElementType,
101 class OtherCriticalSection,
102 typename = AllowConversion<OtherElementType, OtherCriticalSection>>
103 ArrayBase& operator= (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
104 {
105 // No need to worry about assignment to *this, because 'other' must be of a different type.
106 elements = std::move (other.elements);
107 numAllocated = other.numAllocated;
108 numUsed = other.numUsed;
109
110 other.numAllocated = 0;
111 other.numUsed = 0;
112
113 return *this;
114 }
115
116 //==============================================================================
117 template <class OtherArrayType>
118 bool operator== (const OtherArrayType& other) const noexcept
119 {
120 if (size() != (int) other.size())
121 return false;
122
123 auto* e = begin();
124
125 for (auto& o : other)
126 if (! exactlyEqual (*e++, o))
127 return false;
128
129 return true;
130 }
131
132 template <class OtherArrayType>
133 bool operator!= (const OtherArrayType& other) const noexcept
134 {
135 return ! operator== (other);
136 }
137
138 //==============================================================================
139 inline ElementType& operator[] (const int index) noexcept
140 {
141 jassert (elements != nullptr);
142 jassert (isPositiveAndBelow (index, numUsed));
143 return elements[index];
144 }
145
146 inline const ElementType& operator[] (const int index) const noexcept
147 {
148 jassert (elements != nullptr);
149 jassert (isPositiveAndBelow (index, numUsed));
150 return elements[index];
151 }
152
153 inline ElementType getValueWithDefault (const int index) const noexcept
154 {
155 return isPositiveAndBelow (index, numUsed) ? elements[index] : ElementType();
156 }
157
158 inline ElementType getFirst() const noexcept
159 {
160 return numUsed > 0 ? elements[0] : ElementType();
161 }
162
163 inline ElementType getLast() const noexcept
164 {
165 return numUsed > 0 ? elements[numUsed - 1] : ElementType();
166 }
167
168 //==============================================================================
169 inline ElementType* begin() noexcept
170 {
171 return elements;
172 }
173
174 inline const ElementType* begin() const noexcept
175 {
176 return elements;
177 }
178
179 inline ElementType* end() noexcept
180 {
181 return elements + numUsed;
182 }
183
184 inline const ElementType* end() const noexcept
185 {
186 return elements + numUsed;
187 }
188
189 inline ElementType* data() noexcept
190 {
191 return elements;
192 }
193
194 inline const ElementType* data() const noexcept
195 {
196 return elements;
197 }
198
199 inline int size() const noexcept
200 {
201 return numUsed;
202 }
203
204 inline int capacity() const noexcept
205 {
206 return numAllocated;
207 }
208
209 //==============================================================================
210 void setAllocatedSize (int numElements)
211 {
212 jassert (numElements >= numUsed);
213
214 if (numAllocated != numElements)
215 {
216 if (numElements > 0)
217 setAllocatedSizeInternal (numElements);
218 else
219 elements.free();
220 }
221
222 numAllocated = numElements;
223 }
224
225 void ensureAllocatedSize (int minNumElements)
226 {
227 if (minNumElements > numAllocated)
228 setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
229
230 jassert (numAllocated <= 0 || elements != nullptr);
231 }
232
233 void shrinkToNoMoreThan (int maxNumElements)
234 {
235 if (maxNumElements < numAllocated)
236 setAllocatedSize (maxNumElements);
237 }
238
239 void clear()
240 {
241 for (int i = 0; i < numUsed; ++i)
242 elements[i].~ElementType();
243
244 numUsed = 0;
245 }
246
247 //==============================================================================
248 void swapWith (ArrayBase& other) noexcept
249 {
250 elements.swapWith (other.elements);
251 std::swap (numAllocated, other.numAllocated);
252 std::swap (numUsed, other.numUsed);
253 }
254
255 //==============================================================================
256 void add (const ElementType& newElement)
257 {
258 addImpl (newElement);
259 }
260
261 void add (ElementType&& newElement)
262 {
263 addImpl (std::move (newElement));
264 }
265
266 template <typename... OtherElements>
267 void add (const ElementType& firstNewElement, OtherElements&&... otherElements)
268 {
269 addImpl (firstNewElement, std::forward<OtherElements> (otherElements)...);
270 }
271
272 template <typename... OtherElements>
273 void add (ElementType&& firstNewElement, OtherElements&&... otherElements)
274 {
275 addImpl (std::move (firstNewElement), std::forward<OtherElements> (otherElements)...);
276 }
277
278 //==============================================================================
279 template <typename Type>
280 void addArray (const Type* elementsToAdd, int numElementsToAdd)
281 {
282 ensureAllocatedSize (numUsed + numElementsToAdd);
283 addArrayInternal (elementsToAdd, numElementsToAdd);
284 numUsed += numElementsToAdd;
285 }
286
287 template <typename TypeToCreateFrom>
288 void addArray (const std::initializer_list<TypeToCreateFrom>& items)
289 {
290 ensureAllocatedSize (numUsed + (int) items.size());
291
292 for (auto& item : items)
293 new (elements + numUsed++) ElementType (item);
294 }
295
296 template <class OtherArrayType>
297 void addArray (const OtherArrayType& arrayToAddFrom)
298 {
299 jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
300 ensureAllocatedSize (numUsed + (int) arrayToAddFrom.size());
301
302 for (auto& e : arrayToAddFrom)
303 addAssumingCapacityIsReady (e);
304 }
305
306 template <class OtherArrayType>
307 std::enable_if_t<! std::is_pointer_v<OtherArrayType>, int>
308 addArray (const OtherArrayType& arrayToAddFrom,
309 int startIndex, int numElementsToAdd = -1)
310 {
311 jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
312
313 if (startIndex < 0)
314 {
315 jassertfalse;
316 startIndex = 0;
317 }
318
319 if (numElementsToAdd < 0 || startIndex + numElementsToAdd > (int) arrayToAddFrom.size())
320 numElementsToAdd = (int) arrayToAddFrom.size() - startIndex;
321
322 addArray (arrayToAddFrom.data() + startIndex, numElementsToAdd);
323
324 return numElementsToAdd;
325 }
326
327 //==============================================================================
328 void insert (int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
329 {
330 checkSourceIsNotAMember (newElement);
331 auto* space = createInsertSpace (indexToInsertAt, numberOfTimesToInsertIt);
332
333 for (int i = 0; i < numberOfTimesToInsertIt; ++i)
334 new (space++) ElementType (newElement);
335
336 numUsed += numberOfTimesToInsertIt;
337 }
338
339 void insertArray (int indexToInsertAt, const ElementType* newElements, int numberOfElements)
340 {
341 auto* space = createInsertSpace (indexToInsertAt, numberOfElements);
342
343 for (int i = 0; i < numberOfElements; ++i)
344 new (space++) ElementType (*(newElements++));
345
346 numUsed += numberOfElements;
347 }
348
349 //==============================================================================
350 void removeElements (int indexToRemoveAt, int numElementsToRemove)
351 {
352 jassert (indexToRemoveAt >= 0);
353 jassert (numElementsToRemove >= 0);
354 jassert (indexToRemoveAt + numElementsToRemove <= numUsed);
355
356 if (numElementsToRemove > 0)
357 {
358 removeElementsInternal (indexToRemoveAt, numElementsToRemove);
359 numUsed -= numElementsToRemove;
360 }
361 }
362
363 //==============================================================================
364 void swap (int index1, int index2)
365 {
366 if (isPositiveAndBelow (index1, numUsed)
367 && isPositiveAndBelow (index2, numUsed))
368 {
369 std::swap (elements[index1],
370 elements[index2]);
371 }
372 }
373
374 //==============================================================================
375 void move (int currentIndex, int newIndex) noexcept
376 {
377 if (isPositiveAndBelow (currentIndex, numUsed))
378 {
379 if (! isPositiveAndBelow (newIndex, numUsed))
380 newIndex = numUsed - 1;
381
382 moveInternal (currentIndex, newIndex);
383 }
384 }
385
386private:
387 //==============================================================================
388 #if defined (__GNUC__) && __GNUC__ < 5 && ! defined (__clang__)
389 static constexpr auto isTriviallyCopyable = std::is_scalar_v<ElementType>;
390 #else
391 static constexpr auto isTriviallyCopyable = std::is_trivially_copyable_v<ElementType>;
392 #endif
393
394 //==============================================================================
395 template <typename Type>
396 void addArrayInternal (const Type* otherElements, int numElements)
397 {
398 if constexpr (isTriviallyCopyable && std::is_same_v<Type, ElementType>)
399 {
400 if (numElements > 0)
401 memcpy (elements + numUsed, otherElements, (size_t) numElements * sizeof (ElementType));
402 }
403 else
404 {
405 auto* start = elements + numUsed;
406
407 while (--numElements >= 0)
408 new (start++) ElementType (*(otherElements++));
409 }
410 }
411
412 //==============================================================================
413 void setAllocatedSizeInternal (int numElements)
414 {
415 if constexpr (isTriviallyCopyable)
416 {
417 elements.realloc ((size_t) numElements);
418 }
419 else
420 {
421 HeapBlock<ElementType> newElements (numElements);
422
423 for (int i = 0; i < numUsed; ++i)
424 {
425 new (newElements + i) ElementType (std::move (elements[i]));
426 elements[i].~ElementType();
427 }
428
429 elements = std::move (newElements);
430 }
431 }
432
433 //==============================================================================
434 ElementType* createInsertSpace (int indexToInsertAt, int numElements)
435 {
436 ensureAllocatedSize (numUsed + numElements);
437
438 if (! isPositiveAndBelow (indexToInsertAt, numUsed))
439 return elements + numUsed;
440
441 createInsertSpaceInternal (indexToInsertAt, numElements);
442
443 return elements + indexToInsertAt;
444 }
445
446 void createInsertSpaceInternal (int indexToInsertAt, int numElements)
447 {
448 if constexpr (isTriviallyCopyable)
449 {
450 auto* start = elements + indexToInsertAt;
451 auto numElementsToShift = numUsed - indexToInsertAt;
452 memmove (start + numElements, start, (size_t) numElementsToShift * sizeof (ElementType));
453 }
454 else
455 {
456 auto* end = elements + numUsed;
457 auto* newEnd = end + numElements;
458 auto numElementsToShift = numUsed - indexToInsertAt;
459
460 for (int i = 0; i < numElementsToShift; ++i)
461 {
462 new (--newEnd) ElementType (std::move (*(--end)));
463 end->~ElementType();
464 }
465 }
466 }
467
468 //==============================================================================
469 void removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
470 {
471 if constexpr (isTriviallyCopyable)
472 {
473 auto* start = elements + indexToRemoveAt;
474 auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
475 memmove (start, start + numElementsToRemove, (size_t) numElementsToShift * sizeof (ElementType));
476 }
477 else
478 {
479 auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
480 auto* destination = elements + indexToRemoveAt;
481 auto* source = destination + numElementsToRemove;
482
483 for (int i = 0; i < numElementsToShift; ++i)
484 moveAssignElement (destination++, std::move (*(source++)));
485
486 for (int i = 0; i < numElementsToRemove; ++i)
487 (destination++)->~ElementType();
488 }
489 }
490
491 //==============================================================================
492 void moveInternal (int currentIndex, int newIndex) noexcept
493 {
494 if constexpr (isTriviallyCopyable)
495 {
496 char tempCopy[sizeof (ElementType)];
497 memcpy (tempCopy, elements + currentIndex, sizeof (ElementType));
498
499 if (newIndex > currentIndex)
500 {
501 memmove (elements + currentIndex,
502 elements + currentIndex + 1,
503 (size_t) (newIndex - currentIndex) * sizeof (ElementType));
504 }
505 else
506 {
507 memmove (elements + newIndex + 1,
508 elements + newIndex,
509 (size_t) (currentIndex - newIndex) * sizeof (ElementType));
510 }
511
512 memcpy (elements + newIndex, tempCopy, sizeof (ElementType));
513 }
514 else
515 {
516 auto* e = elements + currentIndex;
517 ElementType tempCopy (std::move (*e));
518 auto delta = newIndex - currentIndex;
519
520 if (delta > 0)
521 {
522 for (int i = 0; i < delta; ++i)
523 {
524 moveAssignElement (e, std::move (*(e + 1)));
525 ++e;
526 }
527 }
528 else
529 {
530 for (int i = 0; i < -delta; ++i)
531 {
532 moveAssignElement (e, std::move (*(e - 1)));
533 --e;
534 }
535 }
536
537 moveAssignElement (e, std::move (tempCopy));
538 }
539 }
540
541 //==============================================================================
542 template <typename... Elements>
543 void addImpl (Elements&&... toAdd)
544 {
545 (checkSourceIsNotAMember (toAdd), ...);
546 ensureAllocatedSize (numUsed + (int) sizeof... (toAdd));
547 addAssumingCapacityIsReady (std::forward<Elements> (toAdd)...);
548 }
549
550 template <typename... Elements>
551 void addAssumingCapacityIsReady (Elements&&... toAdd)
552 {
553 (new (elements + numUsed++) ElementType (std::forward<Elements> (toAdd)), ...);
554 }
555
556 //==============================================================================
557 void moveAssignElement (ElementType* destination, ElementType&& source)
558 {
559 if constexpr (std::is_move_assignable_v<ElementType>)
560 {
561 *destination = std::move (source);
562 }
563 else
564 {
565 destination->~ElementType();
566 new (destination) ElementType (std::move (source));
567 }
568 }
569
570 void checkSourceIsNotAMember ([[maybe_unused]] const ElementType& element)
571 {
572 // when you pass a reference to an existing element into a method like add() which
573 // may need to reallocate the array to make more space, the incoming reference may
574 // be deleted indirectly during the reallocation operation! To work around this,
575 // make a local copy of the item you're trying to add (and maybe use std::move to
576 // move it into the add() method to avoid any extra overhead)
577 jassert (std::addressof (element) < begin() || end() <= std::addressof (element));
578 }
579
580 //==============================================================================
581 HeapBlock<ElementType> elements;
582 int numAllocated = 0, numUsed = 0;
583
584 template <class OtherElementType, class OtherCriticalSection>
585 friend class ArrayBase;
586
587 JUCE_DECLARE_NON_COPYABLE (ArrayBase)
588};
589
590} // namespace juce
ArrayBase(ArrayBase< OtherElementType, OtherCriticalSection > &&other) noexcept