43 using ParameterType =
typename TypeHelpers::ParameterType<ElementType>::type;
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>>>;
59 : elements (std::move (other.elements)),
60 numAllocated (other.numAllocated),
61 numUsed (other.numUsed)
63 other.numAllocated = 0;
71 auto tmp (std::move (other));
83 template <
class OtherElementType,
84 class OtherCriticalSection,
85 typename = AllowConversion<OtherElementType, OtherCriticalSection>>
87 : elements (std::move (other.elements)),
88 numAllocated (other.numAllocated),
89 numUsed (other.numUsed)
91 other.numAllocated = 0;
100 template <
class OtherElementType,
101 class OtherCriticalSection,
102 typename = AllowConversion<OtherElementType, OtherCriticalSection>>
106 elements = std::move (other.elements);
107 numAllocated = other.numAllocated;
108 numUsed = other.numUsed;
110 other.numAllocated = 0;
117 template <
class OtherArrayType>
118 bool operator== (
const OtherArrayType& other)
const noexcept
120 if (size() != (
int) other.size())
125 for (
auto& o : other)
126 if (! exactlyEqual (*e++, o))
132 template <
class OtherArrayType>
133 bool operator!= (
const OtherArrayType& other)
const noexcept
135 return ! operator== (other);
139 inline ElementType& operator[] (
const int index)
noexcept
141 jassert (elements !=
nullptr);
142 jassert (isPositiveAndBelow (index, numUsed));
143 return elements[index];
146 inline const ElementType& operator[] (
const int index)
const noexcept
148 jassert (elements !=
nullptr);
149 jassert (isPositiveAndBelow (index, numUsed));
150 return elements[index];
153 inline ElementType getValueWithDefault (
const int index)
const noexcept
155 return isPositiveAndBelow (index, numUsed) ? elements[index] : ElementType();
158 inline ElementType getFirst() const noexcept
160 return numUsed > 0 ? elements[0] : ElementType();
163 inline ElementType getLast() const noexcept
165 return numUsed > 0 ? elements[numUsed - 1] : ElementType();
169 inline ElementType* begin() noexcept
174 inline const ElementType* begin() const noexcept
179 inline ElementType* end() noexcept
181 return elements + numUsed;
184 inline const ElementType* end() const noexcept
186 return elements + numUsed;
189 inline ElementType* data() noexcept
194 inline const ElementType* data() const noexcept
199 inline int size() const noexcept
204 inline int capacity() const noexcept
210 void setAllocatedSize (
int numElements)
212 jassert (numElements >= numUsed);
214 if (numAllocated != numElements)
217 setAllocatedSizeInternal (numElements);
222 numAllocated = numElements;
225 void ensureAllocatedSize (
int minNumElements)
227 if (minNumElements > numAllocated)
228 setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
230 jassert (numAllocated <= 0 || elements !=
nullptr);
233 void shrinkToNoMoreThan (
int maxNumElements)
235 if (maxNumElements < numAllocated)
236 setAllocatedSize (maxNumElements);
241 for (
int i = 0; i < numUsed; ++i)
242 elements[i].~ElementType();
248 void swapWith (ArrayBase& other)
noexcept
250 elements.swapWith (other.elements);
251 std::swap (numAllocated, other.numAllocated);
252 std::swap (numUsed, other.numUsed);
256 void add (
const ElementType& newElement)
258 addImpl (newElement);
261 void add (ElementType&& newElement)
263 addImpl (std::move (newElement));
266 template <
typename... OtherElements>
267 void add (
const ElementType& firstNewElement, OtherElements&&... otherElements)
269 addImpl (firstNewElement, std::forward<OtherElements> (otherElements)...);
272 template <
typename... OtherElements>
273 void add (ElementType&& firstNewElement, OtherElements&&... otherElements)
275 addImpl (std::move (firstNewElement), std::forward<OtherElements> (otherElements)...);
279 template <
typename Type>
280 void addArray (
const Type* elementsToAdd,
int numElementsToAdd)
282 ensureAllocatedSize (numUsed + numElementsToAdd);
283 addArrayInternal (elementsToAdd, numElementsToAdd);
284 numUsed += numElementsToAdd;
287 template <
typename TypeToCreateFrom>
288 void addArray (
const std::initializer_list<TypeToCreateFrom>& items)
290 ensureAllocatedSize (numUsed + (
int) items.size());
292 for (
auto& item : items)
293 new (elements + numUsed++) ElementType (item);
296 template <
class OtherArrayType>
297 void addArray (
const OtherArrayType& arrayToAddFrom)
299 jassert ((
const void*)
this != (
const void*) &arrayToAddFrom);
300 ensureAllocatedSize (numUsed + (
int) arrayToAddFrom.size());
302 for (
auto& e : arrayToAddFrom)
303 addAssumingCapacityIsReady (e);
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)
311 jassert ((
const void*)
this != (
const void*) &arrayToAddFrom);
319 if (numElementsToAdd < 0 || startIndex + numElementsToAdd > (
int) arrayToAddFrom.size())
320 numElementsToAdd = (int) arrayToAddFrom.size() - startIndex;
322 addArray (arrayToAddFrom.data() + startIndex, numElementsToAdd);
324 return numElementsToAdd;
328 void insert (
int indexToInsertAt, ParameterType newElement,
int numberOfTimesToInsertIt)
330 checkSourceIsNotAMember (newElement);
331 auto* space = createInsertSpace (indexToInsertAt, numberOfTimesToInsertIt);
333 for (
int i = 0; i < numberOfTimesToInsertIt; ++i)
334 new (space++) ElementType (newElement);
336 numUsed += numberOfTimesToInsertIt;
339 void insertArray (
int indexToInsertAt,
const ElementType* newElements,
int numberOfElements)
341 auto* space = createInsertSpace (indexToInsertAt, numberOfElements);
343 for (
int i = 0; i < numberOfElements; ++i)
344 new (space++) ElementType (*(newElements++));
346 numUsed += numberOfElements;
350 void removeElements (
int indexToRemoveAt,
int numElementsToRemove)
352 jassert (indexToRemoveAt >= 0);
353 jassert (numElementsToRemove >= 0);
354 jassert (indexToRemoveAt + numElementsToRemove <= numUsed);
356 if (numElementsToRemove > 0)
358 removeElementsInternal (indexToRemoveAt, numElementsToRemove);
359 numUsed -= numElementsToRemove;
364 void swap (
int index1,
int index2)
366 if (isPositiveAndBelow (index1, numUsed)
367 && isPositiveAndBelow (index2, numUsed))
369 std::swap (elements[index1],
375 void move (
int currentIndex,
int newIndex)
noexcept
377 if (isPositiveAndBelow (currentIndex, numUsed))
379 if (! isPositiveAndBelow (newIndex, numUsed))
380 newIndex = numUsed - 1;
382 moveInternal (currentIndex, newIndex);
388 #if defined (__GNUC__) && __GNUC__ < 5 && ! defined (__clang__)
389 static constexpr auto isTriviallyCopyable = std::is_scalar_v<ElementType>;
391 static constexpr auto isTriviallyCopyable = std::is_trivially_copyable_v<ElementType>;
395 template <
typename Type>
396 void addArrayInternal (
const Type* otherElements,
int numElements)
398 if constexpr (isTriviallyCopyable && std::is_same_v<Type, ElementType>)
401 memcpy (elements + numUsed, otherElements, (
size_t) numElements *
sizeof (ElementType));
405 auto* start = elements + numUsed;
407 while (--numElements >= 0)
408 new (start++) ElementType (*(otherElements++));
413 void setAllocatedSizeInternal (
int numElements)
415 if constexpr (isTriviallyCopyable)
417 elements.realloc ((
size_t) numElements);
421 HeapBlock<ElementType> newElements (numElements);
423 for (
int i = 0; i < numUsed; ++i)
425 new (newElements + i) ElementType (std::move (elements[i]));
426 elements[i].~ElementType();
429 elements = std::move (newElements);
434 ElementType* createInsertSpace (
int indexToInsertAt,
int numElements)
436 ensureAllocatedSize (numUsed + numElements);
438 if (! isPositiveAndBelow (indexToInsertAt, numUsed))
439 return elements + numUsed;
441 createInsertSpaceInternal (indexToInsertAt, numElements);
443 return elements + indexToInsertAt;
446 void createInsertSpaceInternal (
int indexToInsertAt,
int numElements)
448 if constexpr (isTriviallyCopyable)
450 auto* start = elements + indexToInsertAt;
451 auto numElementsToShift = numUsed - indexToInsertAt;
452 memmove (start + numElements, start, (
size_t) numElementsToShift *
sizeof (ElementType));
456 auto* end = elements + numUsed;
457 auto* newEnd = end + numElements;
458 auto numElementsToShift = numUsed - indexToInsertAt;
460 for (
int i = 0; i < numElementsToShift; ++i)
462 new (--newEnd) ElementType (std::move (*(--end)));
469 void removeElementsInternal (
int indexToRemoveAt,
int numElementsToRemove)
471 if constexpr (isTriviallyCopyable)
473 auto* start = elements + indexToRemoveAt;
474 auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
475 memmove (start, start + numElementsToRemove, (
size_t) numElementsToShift *
sizeof (ElementType));
479 auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
480 auto* destination = elements + indexToRemoveAt;
481 auto* source = destination + numElementsToRemove;
483 for (
int i = 0; i < numElementsToShift; ++i)
484 moveAssignElement (destination++, std::move (*(source++)));
486 for (
int i = 0; i < numElementsToRemove; ++i)
487 (destination++)->~ElementType();
492 void moveInternal (
int currentIndex,
int newIndex)
noexcept
494 if constexpr (isTriviallyCopyable)
496 char tempCopy[
sizeof (ElementType)];
497 memcpy (tempCopy, elements + currentIndex,
sizeof (ElementType));
499 if (newIndex > currentIndex)
501 memmove (elements + currentIndex,
502 elements + currentIndex + 1,
503 (
size_t) (newIndex - currentIndex) *
sizeof (ElementType));
507 memmove (elements + newIndex + 1,
509 (
size_t) (currentIndex - newIndex) *
sizeof (ElementType));
512 memcpy (elements + newIndex, tempCopy,
sizeof (ElementType));
516 auto* e = elements + currentIndex;
517 ElementType tempCopy (std::move (*e));
518 auto delta = newIndex - currentIndex;
522 for (
int i = 0; i < delta; ++i)
524 moveAssignElement (e, std::move (*(e + 1)));
530 for (
int i = 0; i < -delta; ++i)
532 moveAssignElement (e, std::move (*(e - 1)));
537 moveAssignElement (e, std::move (tempCopy));
542 template <
typename... Elements>
543 void addImpl (Elements&&... toAdd)
545 (checkSourceIsNotAMember (toAdd), ...);
546 ensureAllocatedSize (numUsed + (
int)
sizeof... (toAdd));
547 addAssumingCapacityIsReady (std::forward<Elements> (toAdd)...);
550 template <
typename... Elements>
551 void addAssumingCapacityIsReady (Elements&&... toAdd)
553 (
new (elements + numUsed++) ElementType (std::forward<Elements> (toAdd)), ...);
557 void moveAssignElement (ElementType* destination, ElementType&& source)
559 if constexpr (std::is_move_assignable_v<ElementType>)
561 *destination = std::move (source);
565 destination->~ElementType();
566 new (destination) ElementType (std::move (source));
570 void checkSourceIsNotAMember ([[maybe_unused]]
const ElementType& element)
577 jassert (std::addressof (element) < begin() || end() <= std::addressof (element));
581 HeapBlock<ElementType> elements;
582 int numAllocated = 0, numUsed = 0;
584 template <
class OtherElementType,
class OtherCriticalSection>
585 friend class ArrayBase;
587 JUCE_DECLARE_NON_COPYABLE (ArrayBase)