Cleanup
[carla.git] / source / modules / water / containers / Array.h
blobe4367c9f26301ded706b9126f7cb5732f0a72715
1 /*
2 ==============================================================================
4 This file is part of the Water library.
5 Copyright (c) 2016 ROLI Ltd.
6 Copyright (C) 2017-2019 Filipe Coelho <falktx@falktx.com>
8 Permission is granted to use this software under the terms of the ISC license
9 http://www.isc.org/downloads/software-support-policy/isc-license/
11 Permission to use, copy, modify, and/or distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 OF THIS SOFTWARE.
23 ==============================================================================
26 #ifndef WATER_ARRAY_H_INCLUDED
27 #define WATER_ARRAY_H_INCLUDED
29 #include "../containers/ArrayAllocationBase.h"
30 #include "../containers/ElementComparator.h"
32 namespace water {
34 //==============================================================================
35 /**
36 Holds a resizable array of primitive or copy-by-value objects.
38 Examples of arrays are: Array<int>, Array<Rectangle> or Array<MyClass*>
40 The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to
41 do so, the class must fulfil these requirements:
42 - it must have a copy constructor and assignment operator
43 - it must be able to be relocated in memory by a memcpy without this causing any problems - so
44 objects whose functionality relies on external pointers or references to themselves can not be used.
46 You can of course have an array of pointers to any kind of object, e.g. Array<MyClass*>, but if
47 you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
48 ReferenceCountedArray class for more powerful ways of holding lists of objects.
50 For holding lists of strings, you can use Array\<String\>, but it's usually better to use the
51 specialised class StringArray, which provides more useful functions.
53 @see OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
55 template <typename ElementType, size_t minimumAllocatedSize = 0>
56 class Array
58 private:
59 typedef PARAMETER_TYPE (ElementType) ParameterType;
61 public:
62 //==============================================================================
63 /** Creates an empty array. */
64 Array() noexcept
65 : data(),
66 numUsed(0)
70 /** Creates a copy of another array.
71 @param other the array to copy
73 Array (const Array<ElementType>& other) noexcept
74 : data(),
75 numUsed(0)
77 CARLA_SAFE_ASSERT_RETURN(data.setAllocatedSize (other.numUsed),);
78 numUsed = other.numUsed;
80 for (int i = 0; i < numUsed; ++i)
81 new (data.elements + i) ElementType (other.data.elements[i]);
84 /** Initalises from a null-terminated C array of values.
86 @param values the array to copy from
88 template <typename TypeToCreateFrom>
89 explicit Array (const TypeToCreateFrom* values) noexcept : numUsed (0)
91 while (*values != TypeToCreateFrom())
93 CARLA_SAFE_ASSERT_BREAK(add (*values++));
97 /** Initalises from a C array of values.
99 @param values the array to copy from
100 @param numValues the number of values in the array
102 template <typename TypeToCreateFrom>
103 Array (const TypeToCreateFrom* values, int numValues) noexcept : numUsed (numValues)
105 CARLA_SAFE_ASSERT_RETURN(data.setAllocatedSize (numValues),);
107 for (int i = 0; i < numValues; ++i)
108 new (data.elements + i) ElementType (values[i]);
111 /** Destructor. */
112 ~Array() noexcept
114 deleteAllElements();
117 /** Copies another array.
118 @param other the array to copy
120 Array& operator= (const Array& other) noexcept
122 if (this != &other)
124 Array<ElementType> otherCopy (other);
125 swapWith (otherCopy);
128 return *this;
131 //==============================================================================
132 /** Compares this array to another one.
133 Two arrays are considered equal if they both contain the same set of
134 elements, in the same order.
135 @param other the other array to compare with
137 template <class OtherArrayType>
138 bool operator== (const OtherArrayType& other) const
140 if (numUsed != other.numUsed)
141 return false;
143 for (int i = numUsed; --i >= 0;)
144 if (! (data.elements [i] == other.data.elements [i]))
145 return false;
147 return true;
150 /** Compares this array to another one.
151 Two arrays are considered equal if they both contain the same set of
152 elements, in the same order.
153 @param other the other array to compare with
155 template <class OtherArrayType>
156 bool operator!= (const OtherArrayType& other) const
158 return ! operator== (other);
161 //==============================================================================
162 /** Removes all elements from the array.
163 This will remove all the elements, and free any storage that the array is
164 using. To clear the array without freeing the storage, use the clearQuick()
165 method instead.
167 @see clearQuick
169 void clear() noexcept
171 deleteAllElements();
172 data.setAllocatedSize (0);
173 numUsed = 0;
176 /** Removes all elements from the array without freeing the array's allocated storage.
177 @see clear
179 void clearQuick() noexcept
181 deleteAllElements();
182 numUsed = 0;
185 //==============================================================================
186 /** Returns the current number of elements in the array. */
187 inline int size() const noexcept
189 return numUsed;
192 /** Returns true if the array is empty, false otherwise. */
193 inline bool isEmpty() const noexcept
195 return size() == 0;
198 /** Returns one of the elements in the array.
199 If the index passed in is beyond the range of valid elements, this
200 will return a default value.
202 If you're certain that the index will always be a valid element, you
203 can call getUnchecked() instead, which is faster.
205 @param index the index of the element being requested (0 is the first element in the array)
206 @see getUnchecked, getFirst, getLast
208 ElementType operator[] (const int index) const
210 if (isPositiveAndBelow (index, numUsed))
212 wassert (data.elements != nullptr);
213 return data.elements [index];
216 return ElementType();
219 /** Returns one of the elements in the array, without checking the index passed in.
221 Unlike the operator[] method, this will try to return an element without
222 checking that the index is within the bounds of the array, so should only
223 be used when you're confident that it will always be a valid index.
225 @param index the index of the element being requested (0 is the first element in the array)
226 @see operator[], getFirst, getLast
228 inline ElementType getUnchecked (const int index) const
230 wassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
231 return data.elements [index];
234 /** Returns a direct reference to one of the elements in the array, without checking the index passed in.
236 This is like getUnchecked, but returns a direct reference to the element, so that
237 you can alter it directly. Obviously this can be dangerous, so only use it when
238 absolutely necessary.
240 @param index the index of the element being requested (0 is the first element in the array)
241 @see operator[], getFirst, getLast
243 inline ElementType& getReference (const int index) const noexcept
245 wassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
246 return data.elements [index];
249 /** Returns the first element in the array, or a default value if the array is empty.
251 @see operator[], getUnchecked, getLast
253 inline ElementType getFirst() const
255 if (numUsed > 0)
257 wassert (data.elements != nullptr);
258 return data.elements[0];
261 return ElementType();
264 /** Returns the last element in the array, or a default value if the array is empty.
266 @see operator[], getUnchecked, getFirst
268 inline ElementType getLast() const
270 if (numUsed > 0)
272 wassert (data.elements != nullptr);
273 return data.elements[numUsed - 1];
276 return ElementType();
279 /** Returns a pointer to the actual array data.
280 This pointer will only be valid until the next time a non-const method
281 is called on the array.
283 inline ElementType* getRawDataPointer() noexcept
285 return data.elements;
288 //==============================================================================
289 /** Returns a pointer to the first element in the array.
290 This method is provided for compatibility with standard C++ iteration mechanisms.
292 inline ElementType* begin() const noexcept
294 return data.elements;
297 /** Returns a pointer to the element which follows the last element in the array.
298 This method is provided for compatibility with standard C++ iteration mechanisms.
300 inline ElementType* end() const noexcept
302 #ifdef DEBUG
303 if (data.elements == nullptr || numUsed <= 0) // (to keep static analysers happy)
304 return data.elements;
305 #endif
307 return data.elements + numUsed;
310 //==============================================================================
311 /** Finds the index of the first element which matches the value passed in.
313 This will search the array for the given object, and return the index
314 of its first occurrence. If the object isn't found, the method will return -1.
316 @param elementToLookFor the value or object to look for
317 @returns the index of the object, or -1 if it's not found
319 int indexOf (ParameterType elementToLookFor) const
321 const ElementType* e = data.elements.getData();
322 const ElementType* const end_ = e + numUsed;
324 for (; e != end_; ++e)
325 if (elementToLookFor == *e)
326 return static_cast<int> (e - data.elements.getData());
328 return -1;
331 /** Returns true if the array contains at least one occurrence of an object.
333 @param elementToLookFor the value or object to look for
334 @returns true if the item is found
336 bool contains (ParameterType elementToLookFor) const
338 const ElementType* e = data.elements.getData();
339 const ElementType* const end_ = e + numUsed;
341 for (; e != end_; ++e)
342 if (elementToLookFor == *e)
343 return true;
345 return false;
348 //==============================================================================
349 /** Appends a new element at the end of the array.
351 @param newElement the new object to add to the array
352 @see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray
354 bool add (const ElementType& newElement) noexcept
356 if (! data.ensureAllocatedSize (static_cast<size_t>(numUsed + 1)))
357 return false;
359 new (data.elements + numUsed++) ElementType (newElement);
360 return true;
363 /** Inserts a new element into the array at a given position.
365 If the index is less than 0 or greater than the size of the array, the
366 element will be added to the end of the array.
367 Otherwise, it will be inserted into the array, moving all the later elements
368 along to make room.
370 @param indexToInsertAt the index at which the new element should be
371 inserted (pass in -1 to add it to the end)
372 @param newElement the new object to add to the array
373 @see add, addSorted, addUsingDefaultSort, set
375 bool insert (int indexToInsertAt, ParameterType newElement) noexcept
377 if (! data.ensureAllocatedSize (numUsed + 1))
378 return false;
380 if (isPositiveAndBelow (indexToInsertAt, numUsed))
382 ElementType* const insertPos = data.elements + indexToInsertAt;
383 const int numberToMove = numUsed - indexToInsertAt;
385 if (numberToMove > 0)
386 data.moveMemory (insertPos + 1, insertPos, numberToMove);
388 new (insertPos) ElementType (newElement);
389 ++numUsed;
391 else
393 new (data.elements + numUsed++) ElementType (newElement);
396 return true;
399 /** Inserts multiple copies of an element into the array at a given position.
401 If the index is less than 0 or greater than the size of the array, the
402 element will be added to the end of the array.
403 Otherwise, it will be inserted into the array, moving all the later elements
404 along to make room.
406 @param indexToInsertAt the index at which the new element should be inserted
407 @param newElement the new object to add to the array
408 @param numberOfTimesToInsertIt how many copies of the value to insert
409 @see insert, add, addSorted, set
411 bool insertMultiple (int indexToInsertAt, ParameterType newElement,
412 int numberOfTimesToInsertIt)
414 if (numberOfTimesToInsertIt > 0)
416 if (! data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt))
417 return false;
419 ElementType* insertPos;
421 if (isPositiveAndBelow (indexToInsertAt, numUsed))
423 insertPos = data.elements + indexToInsertAt;
424 const int numberToMove = numUsed - indexToInsertAt;
425 data.moveMemory (insertPos + numberOfTimesToInsertIt, insertPos, numberToMove);
427 else
429 insertPos = data.elements + numUsed;
432 numUsed += numberOfTimesToInsertIt;
434 while (--numberOfTimesToInsertIt >= 0)
436 new (insertPos) ElementType (newElement);
437 ++insertPos; // NB: this increment is done separately from the
438 // new statement to avoid a compiler bug in VS2014
442 return true;
445 #if 0
446 /** Inserts an array of values into this array at a given position.
448 If the index is less than 0 or greater than the size of the array, the
449 new elements will be added to the end of the array.
450 Otherwise, they will be inserted into the array, moving all the later elements
451 along to make room.
453 @param indexToInsertAt the index at which the first new element should be inserted
454 @param newElements the new values to add to the array
455 @param numberOfElements how many items are in the array
456 @see insert, add, addSorted, set
458 bool insertArray (int indexToInsertAt,
459 const ElementType* newElements,
460 int numberOfElements)
462 if (numberOfElements > 0)
464 if (! data.ensureAllocatedSize (numUsed + numberOfElements))
465 return false;
467 ElementType* insertPos = data.elements;
469 if (isPositiveAndBelow (indexToInsertAt, numUsed))
471 insertPos += indexToInsertAt;
472 const int numberToMove = numUsed - indexToInsertAt;
473 std::memmove (insertPos + numberOfElements, insertPos, (size_t) numberToMove * sizeof (ElementType));
475 else
477 insertPos += numUsed;
480 numUsed += numberOfElements;
482 while (--numberOfElements >= 0)
483 new (insertPos++) ElementType (*newElements++);
486 return true;
488 #endif
490 /** Appends a new element at the end of the array as long as the array doesn't
491 already contain it.
493 If the array already contains an element that matches the one passed in, nothing
494 will be done.
496 @param newElement the new object to add to the array
497 @return true if the element was added to the array; false otherwise.
499 bool addIfNotAlreadyThere (ParameterType newElement)
501 if (contains (newElement))
502 return false;
504 return add (newElement);
507 /** Replaces an element with a new value.
509 If the index is less than zero, this method does nothing.
510 If the index is beyond the end of the array, the item is added to the end of the array.
512 @param indexToChange the index whose value you want to change
513 @param newValue the new value to set for this index.
514 @see add, insert
516 void set (const int indexToChange, ParameterType newValue)
518 wassert (indexToChange >= 0);
520 if (isPositiveAndBelow (indexToChange, numUsed))
522 wassert (data.elements != nullptr);
523 data.elements [indexToChange] = newValue;
525 else if (indexToChange >= 0)
527 data.ensureAllocatedSize (numUsed + 1);
528 new (data.elements + numUsed++) ElementType (newValue);
532 /** Replaces an element with a new value without doing any bounds-checking.
534 This just sets a value directly in the array's internal storage, so you'd
535 better make sure it's in range!
537 @param indexToChange the index whose value you want to change
538 @param newValue the new value to set for this index.
539 @see set, getUnchecked
541 void setUnchecked (const int indexToChange, ParameterType newValue)
543 wassert (isPositiveAndBelow (indexToChange, numUsed));
544 data.elements [indexToChange] = newValue;
547 /** Adds elements from an array to the end of this array.
549 @param elementsToAdd an array of some kind of object from which elements
550 can be constructed.
551 @param numElementsToAdd how many elements are in this other array
552 @see add
554 template <typename Type>
555 void addArray (const Type* elementsToAdd, int numElementsToAdd)
557 if (numElementsToAdd > 0)
559 data.ensureAllocatedSize (numUsed + numElementsToAdd);
561 while (--numElementsToAdd >= 0)
563 new (data.elements + numUsed) ElementType (*elementsToAdd++);
564 ++numUsed;
569 /** Adds elements from a null-terminated array of pointers to the end of this array.
571 @param elementsToAdd an array of pointers to some kind of object from which elements
572 can be constructed. This array must be terminated by a nullptr
573 @see addArray
575 template <typename Type>
576 void addNullTerminatedArray (const Type* const* elementsToAdd)
578 int num = 0;
579 for (const Type* const* e = elementsToAdd; *e != nullptr; ++e)
580 ++num;
582 addArray (elementsToAdd, num);
585 /** This swaps the contents of this array with those of another array.
587 If you need to exchange two arrays, this is vastly quicker than using copy-by-value
588 because it just swaps their internal pointers.
590 template <class OtherArrayType>
591 void swapWith (OtherArrayType& otherArray) noexcept
593 data.swapWith (otherArray.data);
594 std::swap (numUsed, otherArray.numUsed);
597 /** Adds elements from another array to the end of this array.
599 @param arrayToAddFrom the array from which to copy the elements
600 @param startIndex the first element of the other array to start copying from
601 @param numElementsToAdd how many elements to add from the other array. If this
602 value is negative or greater than the number of available elements,
603 all available elements will be copied.
604 @see add
606 template <class OtherArrayType>
607 void addArray (const OtherArrayType& arrayToAddFrom,
608 int startIndex = 0,
609 int numElementsToAdd = -1)
611 if (startIndex < 0)
613 wassertfalse;
614 startIndex = 0;
617 if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
618 numElementsToAdd = arrayToAddFrom.size() - startIndex;
620 while (--numElementsToAdd >= 0)
621 add (arrayToAddFrom.getUnchecked (startIndex++));
624 /** This will enlarge or shrink the array to the given number of elements, by adding
625 or removing items from its end.
627 If the array is smaller than the given target size, empty elements will be appended
628 until its size is as specified. If its size is larger than the target, items will be
629 removed from its end to shorten it.
631 void resize (const int targetNumItems)
633 wassert (targetNumItems >= 0);
635 const int numToAdd = targetNumItems - numUsed;
636 if (numToAdd > 0)
637 insertMultiple (numUsed, ElementType(), numToAdd);
638 else if (numToAdd < 0)
639 removeRange (targetNumItems, -numToAdd);
642 /** Inserts a new element into the array, assuming that the array is sorted.
644 This will use a comparator to find the position at which the new element
645 should go. If the array isn't sorted, the behaviour of this
646 method will be unpredictable.
648 @param comparator the comparator to use to compare the elements - see the sort()
649 method for details about the form this object should take
650 @param newElement the new element to insert to the array
651 @returns the index at which the new item was added
652 @see addUsingDefaultSort, add, sort
654 template <class ElementComparator>
655 int addSorted (ElementComparator& comparator, ParameterType newElement)
657 const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newElement, 0, numUsed);
658 insert (index, newElement);
659 return index;
662 /** Inserts a new element into the array, assuming that the array is sorted.
664 This will use the DefaultElementComparator class for sorting, so your ElementType
665 must be suitable for use with that class. If the array isn't sorted, the behaviour of this
666 method will be unpredictable.
668 @param newElement the new element to insert to the array
669 @see addSorted, sort
671 void addUsingDefaultSort (ParameterType newElement)
673 DefaultElementComparator <ElementType> comparator;
674 addSorted (comparator, newElement);
677 /** Finds the index of an element in the array, assuming that the array is sorted.
679 This will use a comparator to do a binary-chop to find the index of the given
680 element, if it exists. If the array isn't sorted, the behaviour of this
681 method will be unpredictable.
683 @param comparator the comparator to use to compare the elements - see the sort()
684 method for details about the form this object should take
685 @param elementToLookFor the element to search for
686 @returns the index of the element, or -1 if it's not found
687 @see addSorted, sort
689 template <typename ElementComparator, typename TargetValueType>
690 int indexOfSorted (ElementComparator& comparator, TargetValueType elementToLookFor) const
692 ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
693 // avoids getting warning messages about the parameter being unused
695 for (int s = 0, e = numUsed;;)
697 if (s >= e)
698 return -1;
700 if (comparator.compareElements (elementToLookFor, data.elements [s]) == 0)
701 return s;
703 const int halfway = (s + e) / 2;
704 if (halfway == s)
705 return -1;
707 if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0)
708 s = halfway;
709 else
710 e = halfway;
714 //==============================================================================
715 /** Removes an element from the array.
717 This will remove the element at a given index, and move back
718 all the subsequent elements to close the gap.
719 If the index passed in is out-of-range, nothing will happen.
721 @param indexToRemove the index of the element to remove
722 @see removeAndReturn, removeFirstMatchingValue, removeAllInstancesOf, removeRange
724 void remove (int indexToRemove)
726 if (isPositiveAndBelow (indexToRemove, numUsed))
728 wassert (data.elements != nullptr);
729 removeInternal (indexToRemove);
733 /** Removes an element from the array.
735 This will remove the element at a given index, and move back
736 all the subsequent elements to close the gap.
737 If the index passed in is out-of-range, nothing will happen.
739 @param indexToRemove the index of the element to remove
740 @returns the element that has been removed
741 @see removeFirstMatchingValue, removeAllInstancesOf, removeRange
743 ElementType removeAndReturn (const int indexToRemove)
745 if (isPositiveAndBelow (indexToRemove, numUsed))
747 wassert (data.elements != nullptr);
748 ElementType removed (data.elements[indexToRemove]);
749 removeInternal (indexToRemove);
750 return removed;
753 return ElementType();
756 /** Removes an element from the array.
758 This will remove the element pointed to by the given iterator,
759 and move back all the subsequent elements to close the gap.
760 If the iterator passed in does not point to an element within the
761 array, behaviour is undefined.
763 @param elementToRemove a pointer to the element to remove
764 @see removeFirstMatchingValue, removeAllInstancesOf, removeRange, removeIf
766 void remove (const ElementType* elementToRemove)
768 wassert (elementToRemove != nullptr);
769 wassert (data.elements != nullptr);
770 const int indexToRemove = int (elementToRemove - data.elements);
772 if (! isPositiveAndBelow (indexToRemove, numUsed))
774 wassertfalse;
775 return;
778 removeInternal (indexToRemove);
781 /** Removes an item from the array.
783 This will remove the first occurrence of the given element from the array.
784 If the item isn't found, no action is taken.
786 @param valueToRemove the object to try to remove
787 @see remove, removeRange, removeIf
789 void removeFirstMatchingValue (ParameterType valueToRemove)
791 ElementType* const e = data.elements;
793 for (int i = 0; i < numUsed; ++i)
795 if (valueToRemove == e[i])
797 removeInternal (i);
798 break;
803 /** Removes items from the array.
805 This will remove all occurrences of the given element from the array.
806 If no such items are found, no action is taken.
808 @param valueToRemove the object to try to remove
809 @return how many objects were removed.
810 @see remove, removeRange, removeIf
812 int removeAllInstancesOf (ParameterType valueToRemove)
814 int numRemoved = 0;
816 for (int i = numUsed; --i >= 0;)
818 if (valueToRemove == data.elements[i])
820 removeInternal (i);
821 ++numRemoved;
825 return numRemoved;
828 /** Removes items from the array.
830 This will remove all objects from the array that match a condition.
831 If no such items are found, no action is taken.
833 @param predicate the condition when to remove an item. Must be a callable
834 type that takes an ElementType and returns a bool
836 @return how many objects were removed.
837 @see remove, removeRange, removeAllInstancesOf
839 template <typename PredicateType>
840 int removeIf (PredicateType predicate)
842 int numRemoved = 0;
844 for (int i = numUsed; --i >= 0;)
846 if (predicate (data.elements[i]) == true)
848 removeInternal (i);
849 ++numRemoved;
853 return numRemoved;
856 /** Removes a range of elements from the array.
858 This will remove a set of elements, starting from the given index,
859 and move subsequent elements down to close the gap.
861 If the range extends beyond the bounds of the array, it will
862 be safely clipped to the size of the array.
864 @param startIndex the index of the first element to remove
865 @param numberToRemove how many elements should be removed
866 @see remove, removeFirstMatchingValue, removeAllInstancesOf, removeIf
868 void removeRange (int startIndex, int numberToRemove)
870 const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
871 startIndex = jlimit (0, numUsed, startIndex);
872 numberToRemove = endIndex - startIndex;
874 if (numberToRemove > 0)
876 #if 1
877 ElementType* const e = data.elements + startIndex;
879 const int numToShift = numUsed - endIndex;
880 if (numToShift > 0)
881 data.moveMemory (e, e + numberToRemove, numToShift);
883 for (int i = 0; i < numberToRemove; ++i)
884 e[numToShift + i].~ElementType();
885 #else
886 ElementType* dst = data.elements + startIndex;
887 ElementType* src = dst + numberToRemove;
889 const int numToShift = numUsed - endIndex;
890 for (int i = 0; i < numToShift; ++i)
891 data.moveElement (dst++, std::move (*(src++)));
893 for (int i = 0; i < numberToRemove; ++i)
894 (dst++)->~ElementType();
895 #endif
897 numUsed -= numberToRemove;
898 minimiseStorageAfterRemoval();
902 /** Removes the last n elements from the array.
904 @param howManyToRemove how many elements to remove from the end of the array
905 @see remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
907 void removeLast (int howManyToRemove = 1)
909 if (howManyToRemove > numUsed)
910 howManyToRemove = numUsed;
912 for (int i = 1; i <= howManyToRemove; ++i)
913 data.elements [numUsed - i].~ElementType();
915 numUsed -= howManyToRemove;
916 minimiseStorageAfterRemoval();
919 /** Removes any elements which are also in another array.
921 @param otherArray the other array in which to look for elements to remove
922 @see removeValuesNotIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
924 template <class OtherArrayType>
925 void removeValuesIn (const OtherArrayType& otherArray)
927 if (this == &otherArray)
929 clear();
931 else
933 if (otherArray.size() > 0)
935 for (int i = numUsed; --i >= 0;)
936 if (otherArray.contains (data.elements [i]))
937 removeInternal (i);
942 /** Removes any elements which are not found in another array.
944 Only elements which occur in this other array will be retained.
946 @param otherArray the array in which to look for elements NOT to remove
947 @see removeValuesIn, remove, removeFirstMatchingValue, removeAllInstancesOf, removeRange
949 template <class OtherArrayType>
950 void removeValuesNotIn (const OtherArrayType& otherArray)
952 if (this != &otherArray)
954 if (otherArray.size() <= 0)
956 clear();
958 else
960 for (int i = numUsed; --i >= 0;)
961 if (! otherArray.contains (data.elements [i]))
962 removeInternal (i);
967 /** Swaps over two elements in the array.
969 This swaps over the elements found at the two indexes passed in.
970 If either index is out-of-range, this method will do nothing.
972 @param index1 index of one of the elements to swap
973 @param index2 index of the other element to swap
975 void swap (const int index1,
976 const int index2)
978 if (isPositiveAndBelow (index1, numUsed)
979 && isPositiveAndBelow (index2, numUsed))
981 std::swap (data.elements [index1],
982 data.elements [index2]);
986 //==============================================================================
987 /** Reduces the amount of storage being used by the array.
989 Arrays typically allocate slightly more storage than they need, and after
990 removing elements, they may have quite a lot of unused space allocated.
991 This method will reduce the amount of allocated storage to a minimum.
993 bool minimiseStorageOverheads() noexcept
995 return data.shrinkToNoMoreThan (numUsed);
998 /** Increases the array's internal storage to hold a minimum number of elements.
1000 Calling this before adding a large known number of elements means that
1001 the array won't have to keep dynamically resizing itself as the elements
1002 are added, and it'll therefore be more efficient.
1004 bool ensureStorageAllocated (const int minNumElements) noexcept
1006 return data.ensureAllocatedSize (minNumElements);
1009 //==============================================================================
1010 /** Sorts the array using a default comparison operation.
1011 If the type of your elements isn't supported by the DefaultElementComparator class
1012 then you may need to use the other version of sort, which takes a custom comparator.
1014 void sort()
1016 DefaultElementComparator<ElementType> comparator;
1017 sort (comparator);
1020 /** Sorts the elements in the array.
1022 This will use a comparator object to sort the elements into order. The object
1023 passed must have a method of the form:
1024 @code
1025 int compareElements (ElementType first, ElementType second);
1026 @endcode
1028 ..and this method must return:
1029 - a value of < 0 if the first comes before the second
1030 - a value of 0 if the two objects are equivalent
1031 - a value of > 0 if the second comes before the first
1033 To improve performance, the compareElements() method can be declared as static or const.
1035 @param comparator the comparator to use for comparing elements.
1036 @param retainOrderOfEquivalentItems if this is true, then items
1037 which the comparator says are equivalent will be
1038 kept in the order in which they currently appear
1039 in the array. This is slower to perform, but may
1040 be important in some cases. If it's false, a faster
1041 algorithm is used, but equivalent elements may be
1042 rearranged.
1044 @see addSorted, indexOfSorted, sortArray
1046 template <class ElementComparator>
1047 void sort (ElementComparator& comparator,
1048 const bool retainOrderOfEquivalentItems = false)
1050 ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
1051 // avoids getting warning messages about the parameter being unused
1052 sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
1055 private:
1056 //==============================================================================
1057 ArrayAllocationBase <ElementType> data;
1058 int numUsed;
1060 void removeInternal (const int indexToRemove)
1062 --numUsed;
1063 ElementType* const e = data.elements + indexToRemove;
1064 e->~ElementType();
1065 const int numberToShift = numUsed - indexToRemove;
1067 if (numberToShift > 0)
1068 data.moveMemory (e, e + 1, static_cast<size_t>(numberToShift));
1070 minimiseStorageAfterRemoval();
1073 inline void deleteAllElements() noexcept
1075 for (int i = 0; i < numUsed; ++i)
1076 data.elements[i].~ElementType();
1079 void minimiseStorageAfterRemoval()
1081 CARLA_SAFE_ASSERT_RETURN(numUsed >= 0,);
1083 const size_t snumUsed = static_cast<size_t>(numUsed);
1085 if (data.numAllocated > jmax (minimumAllocatedSize, snumUsed * 2U))
1086 data.shrinkToNoMoreThan (jmax (snumUsed, jmax (minimumAllocatedSize, 64U / sizeof (ElementType))));
1092 #endif // WATER_ARRAY_H_INCLUDED