1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - 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 
23 namespace juce
24 {
25 
26 //==============================================================================
27 /** An array designed for holding objects.
28 
29     This holds a list of pointers to objects, and will automatically
30     delete the objects when they are removed from the array, or when the
31     array is itself deleted.
32 
33     Declare it in the form:  OwnedArray<MyObjectClass>
34 
35     ..and then add new objects, e.g.   myOwnedArray.add (new MyObjectClass());
36 
37     After adding objects, they are 'owned' by the array and will be deleted when
38     removed or replaced.
39 
40     To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
41     TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
42 
43     @see Array, ReferenceCountedArray, StringArray, CriticalSection
44 
45     @tags{Core}
46 */
47 template <class ObjectClass,
48           class TypeOfCriticalSectionToUse = DummyCriticalSection>
49 
50 class OwnedArray
51 {
52 public:
53     //==============================================================================
54     /** Creates an empty array. */
55     OwnedArray() = default;
56 
57     /** Deletes the array and also deletes any objects inside it.
58 
59         To get rid of the array without deleting its objects, use its
60         clear (false) method before deleting it.
61     */
~OwnedArray()62     ~OwnedArray()
63     {
64         deleteAllObjects();
65     }
66 
67     /** Move constructor. */
OwnedArray(OwnedArray && other)68     OwnedArray (OwnedArray&& other) noexcept
69         : values (std::move (other.values))
70     {
71     }
72 
73     /** Creates an array from a list of objects. */
OwnedArray(const std::initializer_list<ObjectClass * > & items)74     OwnedArray (const std::initializer_list<ObjectClass*>& items)
75     {
76         addArray (items);
77     }
78 
79     /** Move assignment operator. */
80     OwnedArray& operator= (OwnedArray&& other) noexcept
81     {
82         const ScopedLockType lock (getLock());
83         deleteAllObjects();
84         values = std::move (other.values);
85         return *this;
86     }
87 
88     /** Converting move constructor. */
89     template <class OtherObjectClass, class OtherCriticalSection>
OwnedArray(OwnedArray<OtherObjectClass,OtherCriticalSection> && other)90     OwnedArray (OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
91         : values (std::move (other.values))
92     {
93     }
94 
95     /** Converting move assignment operator. */
96     template <class OtherObjectClass, class OtherCriticalSection>
97     OwnedArray& operator= (OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
98     {
99         const ScopedLockType lock (getLock());
100         deleteAllObjects();
101         values = std::move (other.values);
102         return *this;
103     }
104 
105     //==============================================================================
106     /** Clears the array, optionally deleting the objects inside it first. */
107     void clear (bool deleteObjects = true)
108     {
109         const ScopedLockType lock (getLock());
110         clearQuick (deleteObjects);
111         values.setAllocatedSize (0);
112     }
113 
114     //==============================================================================
115     /** Clears the array, optionally deleting the objects inside it first. */
clearQuick(bool deleteObjects)116     void clearQuick (bool deleteObjects)
117     {
118         const ScopedLockType lock (getLock());
119 
120         if (deleteObjects)
121             deleteAllObjects();
122         else
123             values.clear();
124     }
125 
126     //==============================================================================
127     /** Returns the number of items currently in the array.
128         @see operator[]
129     */
size()130     inline int size() const noexcept
131     {
132         return values.size();
133     }
134 
135     /** Returns true if the array is empty, false otherwise. */
isEmpty()136     inline bool isEmpty() const noexcept
137     {
138         return size() == 0;
139     }
140 
141     /** Returns a pointer to the object at this index in the array.
142 
143         If the index is out-of-range, this will return a null pointer, (and
144         it could be null anyway, because it's ok for the array to hold null
145         pointers as well as objects).
146 
147         @see getUnchecked
148     */
149     inline ObjectClass* operator[] (int index) const noexcept
150     {
151         const ScopedLockType lock (getLock());
152         return values.getValueWithDefault (index);
153     }
154 
155     /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
156 
157         This is a faster and less safe version of operator[] which doesn't check the index passed in, so
158         it can be used when you're sure the index is always going to be legal.
159     */
getUnchecked(int index)160     inline ObjectClass* getUnchecked (int index) const noexcept
161     {
162         const ScopedLockType lock (getLock());
163         return values[index];
164     }
165 
166     /** Returns a pointer to the first object in the array.
167 
168         This will return a null pointer if the array's empty.
169         @see getLast
170     */
getFirst()171     inline ObjectClass* getFirst() const noexcept
172     {
173         const ScopedLockType lock (getLock());
174         return values.getFirst();
175     }
176 
177     /** Returns a pointer to the last object in the array.
178 
179         This will return a null pointer if the array's empty.
180         @see getFirst
181     */
getLast()182     inline ObjectClass* getLast() const noexcept
183     {
184         const ScopedLockType lock (getLock());
185         return values.getLast();
186     }
187 
188     /** Returns a pointer to the actual array data.
189         This pointer will only be valid until the next time a non-const method
190         is called on the array.
191     */
getRawDataPointer()192     inline ObjectClass** getRawDataPointer() noexcept
193     {
194         return values.begin();
195     }
196 
197     //==============================================================================
198     /** Returns a pointer to the first element in the array.
199         This method is provided for compatibility with standard C++ iteration mechanisms.
200     */
begin()201     inline ObjectClass** begin() noexcept
202     {
203         return values.begin();
204     }
205 
206     /** Returns a pointer to the first element in the array.
207         This method is provided for compatibility with standard C++ iteration mechanisms.
208     */
begin()209     inline ObjectClass* const* begin() const noexcept
210     {
211         return values.begin();
212     }
213 
214     /** Returns a pointer to the element which follows the last element in the array.
215         This method is provided for compatibility with standard C++ iteration mechanisms.
216     */
end()217     inline ObjectClass** end() noexcept
218     {
219         return values.end();
220     }
221 
222     /** Returns a pointer to the element which follows the last element in the array.
223         This method is provided for compatibility with standard C++ iteration mechanisms.
224     */
end()225     inline ObjectClass* const* end() const noexcept
226     {
227         return values.end();
228     }
229 
230     /** Returns a pointer to the first element in the array.
231         This method is provided for compatibility with the standard C++ containers.
232     */
data()233     inline ObjectClass** data() noexcept
234     {
235         return begin();
236     }
237 
238     /** Returns a pointer to the first element in the array.
239         This method is provided for compatibility with the standard C++ containers.
240     */
data()241     inline ObjectClass* const* data() const noexcept
242     {
243         return begin();
244     }
245 
246     //==============================================================================
247     /** Finds the index of an object which might be in the array.
248 
249         @param objectToLookFor    the object to look for
250         @returns                  the index at which the object was found, or -1 if it's not found
251     */
indexOf(const ObjectClass * objectToLookFor)252     int indexOf (const ObjectClass* objectToLookFor) const noexcept
253     {
254         const ScopedLockType lock (getLock());
255         auto* e = values.begin();
256 
257         for (; e != values.end(); ++e)
258             if (objectToLookFor == *e)
259                 return static_cast<int> (e - values.begin());
260 
261         return -1;
262     }
263 
264     /** Returns true if the array contains a specified object.
265 
266         @param objectToLookFor      the object to look for
267         @returns                    true if the object is in the array
268     */
contains(const ObjectClass * objectToLookFor)269     bool contains (const ObjectClass* objectToLookFor) const noexcept
270     {
271         const ScopedLockType lock (getLock());
272         auto* e = values.begin();
273 
274         for (; e != values.end(); ++e)
275             if (objectToLookFor == *e)
276                 return true;
277 
278         return false;
279     }
280 
281     //==============================================================================
282     /** Appends a new object to the end of the array.
283 
284         Note that this object will be deleted by the OwnedArray when it is removed,
285         so be careful not to delete it somewhere else.
286 
287         Also be careful not to add the same object to the array more than once,
288         as this will obviously cause deletion of dangling pointers.
289 
290         @param newObject    the new object to add to the array
291         @returns            the new object that was added
292         @see set, insert, addSorted
293     */
add(ObjectClass * newObject)294     ObjectClass* add (ObjectClass* newObject)
295     {
296         const ScopedLockType lock (getLock());
297         values.add (newObject);
298         return newObject;
299     }
300 
301     /** Appends a new object to the end of the array.
302 
303         Note that this object will be deleted by the OwnedArray when it is removed,
304         so be careful not to delete it somewhere else.
305 
306         Also be careful not to add the same object to the array more than once,
307         as this will obviously cause deletion of dangling pointers.
308 
309         @param newObject    the new object to add to the array
310         @returns            the new object that was added
311         @see set, insert, addSorted
312     */
add(std::unique_ptr<ObjectClass> newObject)313     ObjectClass* add (std::unique_ptr<ObjectClass> newObject)
314     {
315         return add (newObject.release());
316     }
317 
318     /** Inserts a new object into the array at the given index.
319 
320         Note that this object will be deleted by the OwnedArray when it is removed,
321         so be careful not to delete it somewhere else.
322 
323         If the index is less than 0 or greater than the size of the array, the
324         element will be added to the end of the array.
325         Otherwise, it will be inserted into the array, moving all the later elements
326         along to make room.
327 
328         Be careful not to add the same object to the array more than once,
329         as this will obviously cause deletion of dangling pointers.
330 
331         @param indexToInsertAt      the index at which the new element should be inserted
332         @param newObject            the new object to add to the array
333         @returns                    the new object that was added
334         @see add, addSorted, set
335     */
insert(int indexToInsertAt,ObjectClass * newObject)336     ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject)
337     {
338         const ScopedLockType lock (getLock());
339         values.insert (indexToInsertAt, newObject, 1);
340         return newObject;
341     }
342 
343     /** Inserts a new object into the array at the given index.
344 
345         Note that this object will be deleted by the OwnedArray when it is removed,
346         so be careful not to delete it somewhere else.
347 
348         If the index is less than 0 or greater than the size of the array, the
349         element will be added to the end of the array.
350         Otherwise, it will be inserted into the array, moving all the later elements
351         along to make room.
352 
353         Be careful not to add the same object to the array more than once,
354         as this will obviously cause deletion of dangling pointers.
355 
356         @param indexToInsertAt      the index at which the new element should be inserted
357         @param newObject            the new object to add to the array
358         @returns                    the new object that was added
359         @see add, addSorted, set
360     */
insert(int indexToInsertAt,std::unique_ptr<ObjectClass> newObject)361     ObjectClass* insert (int indexToInsertAt, std::unique_ptr<ObjectClass> newObject)
362     {
363         return insert (indexToInsertAt, newObject.release());
364     }
365 
366     /** Inserts an array of values into this array at a given position.
367 
368         If the index is less than 0 or greater than the size of the array, the
369         new elements will be added to the end of the array.
370         Otherwise, they will be inserted into the array, moving all the later elements
371         along to make room.
372 
373         @param indexToInsertAt      the index at which the first new element should be inserted
374         @param newObjects           the new values to add to the array
375         @param numberOfElements     how many items are in the array
376         @see insert, add, addSorted, set
377     */
insertArray(int indexToInsertAt,ObjectClass * const * newObjects,int numberOfElements)378     void insertArray (int indexToInsertAt,
379                       ObjectClass* const* newObjects,
380                       int numberOfElements)
381     {
382         if (numberOfElements > 0)
383         {
384             const ScopedLockType lock (getLock());
385             values.insertArray (indexToInsertAt, newObjects, numberOfElements);
386         }
387     }
388 
389     /** Replaces an object in the array with a different one.
390 
391         If the index is less than zero, this method does nothing.
392         If the index is beyond the end of the array, the new object is added to the end of the array.
393 
394         Be careful not to add the same object to the array more than once,
395         as this will obviously cause deletion of dangling pointers.
396 
397         @param indexToChange        the index whose value you want to change
398         @param newObject            the new value to set for this index.
399         @param deleteOldElement     whether to delete the object that's being replaced with the new one
400         @see add, insert, remove
401     */
402     ObjectClass* set (int indexToChange, ObjectClass* newObject, bool deleteOldElement = true)
403     {
404         if (indexToChange >= 0)
405         {
406             std::unique_ptr<ObjectClass> toDelete;
407 
408             {
409                 const ScopedLockType lock (getLock());
410 
411                 if (indexToChange < values.size())
412                 {
413                     if (deleteOldElement)
414                     {
415                         toDelete.reset (values[indexToChange]);
416 
417                         if (toDelete.get() == newObject)
418                             toDelete.release();
419                     }
420 
421                     values[indexToChange] = newObject;
422                 }
423                 else
424                 {
425                     values.add (newObject);
426                 }
427             }
428         }
429         else
430         {
431             jassertfalse; // you're trying to set an object at a negative index, which doesn't have
432                           // any effect - but since the object is not being added, it may be leaking..
433         }
434 
435         return newObject;
436     }
437 
438     /** Replaces an object in the array with a different one.
439 
440         If the index is less than zero, this method does nothing.
441         If the index is beyond the end of the array, the new object is added to the end of the array.
442 
443         Be careful not to add the same object to the array more than once,
444         as this will obviously cause deletion of dangling pointers.
445 
446         @param indexToChange        the index whose value you want to change
447         @param newObject            the new value to set for this index.
448         @param deleteOldElement     whether to delete the object that's being replaced with the new one
449         @see add, insert, remove
450     */
451     ObjectClass* set (int indexToChange, std::unique_ptr<ObjectClass> newObject, bool deleteOldElement = true)
452     {
453         return set (indexToChange, newObject.release(), deleteOldElement);
454     }
455 
456     /** Adds elements from another array to the end of this array.
457 
458         @param arrayToAddFrom       the array from which to copy the elements
459         @param startIndex           the first element of the other array to start copying from
460         @param numElementsToAdd     how many elements to add from the other array. If this
461                                     value is negative or greater than the number of available elements,
462                                     all available elements will be copied.
463         @see add
464     */
465     template <class OtherArrayType>
466     void addArray (const OtherArrayType& arrayToAddFrom,
467                    int startIndex = 0,
468                    int numElementsToAdd = -1)
469     {
470         const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
471         const ScopedLockType lock2 (getLock());
472         values.addArray (arrayToAddFrom, startIndex, numElementsToAdd);
473     }
474 
475     /** Adds elements from another array to the end of this array. */
476     template <typename OtherArrayType>
addArray(const std::initializer_list<OtherArrayType> & items)477     void addArray (const std::initializer_list<OtherArrayType>& items)
478     {
479         const ScopedLockType lock (getLock());
480         values.addArray (items);
481     }
482 
483     /** Adds copies of the elements in another array to the end of this array.
484 
485         The other array must be either an OwnedArray of a compatible type of object, or an Array
486         containing pointers to the same kind of object. The objects involved must provide
487         a copy constructor, and this will be used to create new copies of each element, and
488         add them to this array.
489 
490         @param arrayToAddFrom       the array from which to copy the elements
491         @param startIndex           the first element of the other array to start copying from
492         @param numElementsToAdd     how many elements to add from the other array. If this
493                                     value is negative or greater than the number of available elements,
494                                     all available elements will be copied.
495         @see add
496     */
497     template <class OtherArrayType>
498     void addCopiesOf (const OtherArrayType& arrayToAddFrom,
499                       int startIndex = 0,
500                       int numElementsToAdd = -1)
501     {
502         const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
503         const ScopedLockType lock2 (getLock());
504 
505         if (startIndex < 0)
506         {
507             jassertfalse;
508             startIndex = 0;
509         }
510 
511         if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
512             numElementsToAdd = arrayToAddFrom.size() - startIndex;
513 
514         jassert (numElementsToAdd >= 0);
515         values.ensureAllocatedSize (values.size() + numElementsToAdd);
516 
517         while (--numElementsToAdd >= 0)
518             values.add (createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++)));
519     }
520 
521     /** Inserts a new object into the array assuming that the array is sorted.
522 
523         This will use a comparator to find the position at which the new object
524         should go. If the array isn't sorted, the behaviour of this
525         method will be unpredictable.
526 
527         @param comparator   the comparator to use to compare the elements - see the sort method
528                             for details about this object's structure
529         @param newObject    the new object to insert to the array
530         @returns the index at which the new object was added
531         @see add, sort, indexOfSorted
532     */
533     template <class ElementComparator>
addSorted(ElementComparator & comparator,ObjectClass * newObject)534     int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
535     {
536         // If you pass in an object with a static compareElements() method, this
537         // avoids getting warning messages about the parameter being unused
538         ignoreUnused (comparator);
539 
540         const ScopedLockType lock (getLock());
541         auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
542         insert (index, newObject);
543         return index;
544     }
545 
546     /** Finds the index of an object in the array, assuming that the array is sorted.
547 
548         This will use a comparator to do a binary-chop to find the index of the given
549         element, if it exists. If the array isn't sorted, the behaviour of this
550         method will be unpredictable.
551 
552         @param comparator           the comparator to use to compare the elements - see the sort()
553                                     method for details about the form this object should take
554         @param objectToLookFor      the object to search for
555         @returns                    the index of the element, or -1 if it's not found
556         @see addSorted, sort
557     */
558     template <typename ElementComparator>
indexOfSorted(ElementComparator & comparator,const ObjectClass * objectToLookFor)559     int indexOfSorted (ElementComparator& comparator, const ObjectClass* objectToLookFor) const noexcept
560     {
561         // If you pass in an object with a static compareElements() method, this
562         // avoids getting warning messages about the parameter being unused
563         ignoreUnused (comparator);
564 
565         const ScopedLockType lock (getLock());
566         int s = 0, e = values.size();
567 
568         while (s < e)
569         {
570             if (comparator.compareElements (objectToLookFor, values[s]) == 0)
571                 return s;
572 
573             auto halfway = (s + e) / 2;
574 
575             if (halfway == s)
576                 break;
577 
578             if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
579                 s = halfway;
580             else
581                 e = halfway;
582         }
583 
584         return -1;
585     }
586 
587     //==============================================================================
588     /** Removes an object from the array.
589 
590         This will remove the object at a given index (optionally also
591         deleting it) and move back all the subsequent objects to close the gap.
592         If the index passed in is out-of-range, nothing will happen.
593 
594         @param indexToRemove    the index of the element to remove
595         @param deleteObject     whether to delete the object that is removed
596         @see removeObject, removeRange
597     */
598     void remove (int indexToRemove, bool deleteObject = true)
599     {
600         std::unique_ptr<ObjectClass> toDelete;
601 
602         {
603             const ScopedLockType lock (getLock());
604 
605             if (isPositiveAndBelow (indexToRemove, values.size()))
606             {
607                 auto** e = values.begin() + indexToRemove;
608 
609                 if (deleteObject)
610                     toDelete.reset (*e);
611 
612                 values.removeElements (indexToRemove, 1);
613             }
614         }
615 
616         if ((values.size() << 1) < values.capacity())
617             minimiseStorageOverheads();
618     }
619 
620     /** Removes and returns an object from the array without deleting it.
621 
622         This will remove the object at a given index and return it, moving back all
623         the subsequent objects to close the gap. If the index passed in is out-of-range,
624         nothing will happen.
625 
626         @param indexToRemove    the index of the element to remove
627         @see remove, removeObject, removeRange
628     */
removeAndReturn(int indexToRemove)629     ObjectClass* removeAndReturn (int indexToRemove)
630     {
631         ObjectClass* removedItem = nullptr;
632         const ScopedLockType lock (getLock());
633 
634         if (isPositiveAndBelow (indexToRemove, values.size()))
635         {
636            removedItem = values[indexToRemove];
637 
638             values.removeElements (indexToRemove, 1);
639 
640             if ((values.size() << 1) < values.capacity())
641                 minimiseStorageOverheads();
642         }
643 
644         return removedItem;
645     }
646 
647     /** Removes a specified object from the array.
648 
649         If the item isn't found, no action is taken.
650 
651         @param objectToRemove   the object to try to remove
652         @param deleteObject     whether to delete the object (if it's found)
653         @see remove, removeRange
654     */
655     void removeObject (const ObjectClass* objectToRemove, bool deleteObject = true)
656     {
657         const ScopedLockType lock (getLock());
658 
659         for (int i = 0; i < values.size(); ++i)
660         {
661             if (objectToRemove == values[i])
662             {
663                 remove (i, deleteObject);
664                 break;
665             }
666         }
667     }
668 
669     /** Removes a range of objects from the array.
670 
671         This will remove a set of objects, starting from the given index,
672         and move any subsequent elements down to close the gap.
673 
674         If the range extends beyond the bounds of the array, it will
675         be safely clipped to the size of the array.
676 
677         @param startIndex       the index of the first object to remove
678         @param numberToRemove   how many objects should be removed
679         @param deleteObjects    whether to delete the objects that get removed
680         @see remove, removeObject
681     */
682     void removeRange (int startIndex, int numberToRemove, bool deleteObjects = true)
683     {
684         const ScopedLockType lock (getLock());
685         auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
686         startIndex = jlimit (0, values.size(), startIndex);
687         numberToRemove = endIndex - startIndex;
688 
689         if (numberToRemove > 0)
690         {
691             Array<ObjectClass*> objectsToDelete;
692 
693             if (deleteObjects)
694                 objectsToDelete.addArray (values.begin() + startIndex, numberToRemove);
695 
696             values.removeElements (startIndex, numberToRemove);
697 
698             for (auto& o : objectsToDelete)
699                 ContainerDeletePolicy<ObjectClass>::destroy (o);
700 
701             if ((values.size() << 1) < values.capacity())
702                 minimiseStorageOverheads();
703         }
704     }
705 
706     /** Removes the last n objects from the array.
707 
708         @param howManyToRemove   how many objects to remove from the end of the array
709         @param deleteObjects     whether to also delete the objects that are removed
710         @see remove, removeObject, removeRange
711     */
712     void removeLast (int howManyToRemove = 1,
713                      bool deleteObjects = true)
714     {
715         const ScopedLockType lock (getLock());
716 
717         if (howManyToRemove >= values.size())
718             clear (deleteObjects);
719         else
720             removeRange (values.size() - howManyToRemove, howManyToRemove, deleteObjects);
721     }
722 
723     /** Swaps a pair of objects in the array.
724 
725         If either of the indexes passed in is out-of-range, nothing will happen,
726         otherwise the two objects at these positions will be exchanged.
727     */
swap(int index1,int index2)728     void swap (int index1, int index2) noexcept
729     {
730         const ScopedLockType lock (getLock());
731         values.swap (index1, index2);
732     }
733 
734     /** Moves one of the objects to a different position.
735 
736         This will move the object to a specified index, shuffling along
737         any intervening elements as required.
738 
739         So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
740         move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
741 
742         @param currentIndex     the index of the object to be moved. If this isn't a
743                                 valid index, then nothing will be done
744         @param newIndex         the index at which you'd like this object to end up. If this
745                                 is less than zero, it will be moved to the end of the array
746     */
move(int currentIndex,int newIndex)747     void move (int currentIndex, int newIndex) noexcept
748     {
749         if (currentIndex != newIndex)
750         {
751             const ScopedLockType lock (getLock());
752             values.move (currentIndex, newIndex);
753         }
754     }
755 
756     /** This swaps the contents of this array with those of another array.
757 
758         If you need to exchange two arrays, this is vastly quicker than using copy-by-value
759         because it just swaps their internal pointers.
760     */
761     template <class OtherArrayType>
swapWith(OtherArrayType & otherArray)762     void swapWith (OtherArrayType& otherArray) noexcept
763     {
764         const ScopedLockType lock1 (getLock());
765         const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
766         values.swapWith (otherArray.values);
767     }
768 
769     //==============================================================================
770     /** Reduces the amount of storage being used by the array.
771 
772         Arrays typically allocate slightly more storage than they need, and after
773         removing elements, they may have quite a lot of unused space allocated.
774         This method will reduce the amount of allocated storage to a minimum.
775     */
minimiseStorageOverheads()776     void minimiseStorageOverheads() noexcept
777     {
778         const ScopedLockType lock (getLock());
779         values.shrinkToNoMoreThan (values.size());
780     }
781 
782     /** Increases the array's internal storage to hold a minimum number of elements.
783 
784         Calling this before adding a large known number of elements means that
785         the array won't have to keep dynamically resizing itself as the elements
786         are added, and it'll therefore be more efficient.
787     */
ensureStorageAllocated(int minNumElements)788     void ensureStorageAllocated (int minNumElements) noexcept
789     {
790         const ScopedLockType lock (getLock());
791         values.ensureAllocatedSize (minNumElements);
792     }
793 
794     //==============================================================================
795     /** Sorts the elements in the array.
796 
797         This will use a comparator object to sort the elements into order. The object
798         passed must have a method of the form:
799         @code
800         int compareElements (ElementType* first, ElementType* second);
801         @endcode
802 
803         ..and this method must return:
804           - a value of < 0 if the first comes before the second
805           - a value of 0 if the two objects are equivalent
806           - a value of > 0 if the second comes before the first
807 
808         To improve performance, the compareElements() method can be declared as static or const.
809 
810         @param comparator   the comparator to use for comparing elements.
811         @param retainOrderOfEquivalentItems     if this is true, then items
812                             which the comparator says are equivalent will be
813                             kept in the order in which they currently appear
814                             in the array. This is slower to perform, but may
815                             be important in some cases. If it's false, a faster
816                             algorithm is used, but equivalent elements may be
817                             rearranged.
818         @see sortArray, indexOfSorted
819     */
820     template <class ElementComparator>
821     void sort (ElementComparator& comparator,
822                bool retainOrderOfEquivalentItems = false) noexcept
823     {
824         // If you pass in an object with a static compareElements() method, this
825         // avoids getting warning messages about the parameter being unused
826         ignoreUnused (comparator);
827 
828         const ScopedLockType lock (getLock());
829 
830         if (size() > 1)
831             sortArray (comparator, values.begin(), 0, size() - 1, retainOrderOfEquivalentItems);
832     }
833 
834     //==============================================================================
835     /** Returns the CriticalSection that locks this array.
836         To lock, you can call getLock().enter() and getLock().exit(), or preferably use
837         an object of ScopedLockType as an RAII lock for it.
838     */
getLock()839     inline const TypeOfCriticalSectionToUse& getLock() const noexcept      { return values; }
840 
841     /** Returns the type of scoped lock to use for locking this array */
842     using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
843 
844     //==============================================================================
845    #ifndef DOXYGEN
846     // Note that the swapWithArray method has been replaced by a more flexible templated version,
847     // and renamed "swapWith" to be more consistent with the names used in other classes.
848     JUCE_DEPRECATED_WITH_BODY (void swapWithArray (OwnedArray& other) noexcept, { swapWith (other); })
849    #endif
850 
851 private:
852     //==============================================================================
853     ArrayBase <ObjectClass*, TypeOfCriticalSectionToUse> values;
854 
deleteAllObjects()855     void deleteAllObjects()
856     {
857         auto i = values.size();
858 
859         while (--i >= 0)
860         {
861             auto* e = values[i];
862             values.removeElements (i, 1);
863             ContainerDeletePolicy<ObjectClass>::destroy (e);
864         }
865     }
866 
867     template <class OtherObjectClass, class OtherCriticalSection>
868     friend class OwnedArray;
869 
870     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
871 };
872 
873 } // namespace juce
874