OpenShot Audio Library | OpenShotAudio  0.6.0
juce_OwnedArray.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 
23 namespace juce
24 {
25 
26 //==============================================================================
47 template <class ObjectClass,
48  class TypeOfCriticalSectionToUse = DummyCriticalSection>
50 {
51 public:
52  //==============================================================================
54  OwnedArray() = default;
55 
62  {
63  deleteAllObjects();
64  }
65 
67  OwnedArray (OwnedArray&& other) noexcept
68  : values (std::move (other.values))
69  {
70  }
71 
73  OwnedArray (const std::initializer_list<ObjectClass*>& items)
74  {
75  addArray (items);
76  }
77 
79  OwnedArray& operator= (OwnedArray&& other) noexcept
80  {
81  const ScopedLockType lock (getLock());
82  deleteAllObjects();
83  values = std::move (other.values);
84  return *this;
85  }
86 
88  template <class OtherObjectClass, class OtherCriticalSection>
90  : values (std::move (other.values))
91  {
92  }
93 
95  template <class OtherObjectClass, class OtherCriticalSection>
97  {
98  const ScopedLockType lock (getLock());
99  deleteAllObjects();
100  values = std::move (other.values);
101  return *this;
102  }
103 
104  //==============================================================================
106  void clear (bool deleteObjects = true)
107  {
108  const ScopedLockType lock (getLock());
109  clearQuick (deleteObjects);
110  values.setAllocatedSize (0);
111  }
112 
113  //==============================================================================
115  void clearQuick (bool deleteObjects)
116  {
117  const ScopedLockType lock (getLock());
118 
119  if (deleteObjects)
120  deleteAllObjects();
121  else
122  values.clear();
123  }
124 
125  //==============================================================================
129  inline int size() const noexcept
130  {
131  return values.size();
132  }
133 
135  inline bool isEmpty() const noexcept
136  {
137  return size() == 0;
138  }
139 
148  inline ObjectClass* operator[] (int index) const noexcept
149  {
150  const ScopedLockType lock (getLock());
151  return values.getValueWithDefault (index);
152  }
153 
159  inline ObjectClass* getUnchecked (int index) const noexcept
160  {
161  const ScopedLockType lock (getLock());
162  return values[index];
163  }
164 
170  inline ObjectClass* getFirst() const noexcept
171  {
172  const ScopedLockType lock (getLock());
173  return values.getFirst();
174  }
175 
181  inline ObjectClass* getLast() const noexcept
182  {
183  const ScopedLockType lock (getLock());
184  return values.getLast();
185  }
186 
191  inline ObjectClass** getRawDataPointer() noexcept
192  {
193  return values.begin();
194  }
195 
196  //==============================================================================
200  inline ObjectClass** begin() noexcept
201  {
202  return values.begin();
203  }
204 
208  inline ObjectClass* const* begin() const noexcept
209  {
210  return values.begin();
211  }
212 
216  inline ObjectClass** end() noexcept
217  {
218  return values.end();
219  }
220 
224  inline ObjectClass* const* end() const noexcept
225  {
226  return values.end();
227  }
228 
232  inline ObjectClass** data() noexcept
233  {
234  return begin();
235  }
236 
240  inline ObjectClass* const* data() const noexcept
241  {
242  return begin();
243  }
244 
245  //==============================================================================
251  int indexOf (const ObjectClass* objectToLookFor) const noexcept
252  {
253  const ScopedLockType lock (getLock());
254  auto* e = values.begin();
255 
256  for (; e != values.end(); ++e)
257  if (objectToLookFor == *e)
258  return static_cast<int> (e - values.begin());
259 
260  return -1;
261  }
262 
268  bool contains (const ObjectClass* objectToLookFor) const noexcept
269  {
270  const ScopedLockType lock (getLock());
271  auto* e = values.begin();
272 
273  for (; e != values.end(); ++e)
274  if (objectToLookFor == *e)
275  return true;
276 
277  return false;
278  }
279 
280  //==============================================================================
293  ObjectClass* add (ObjectClass* newObject)
294  {
295  const ScopedLockType lock (getLock());
296  values.add (newObject);
297  return newObject;
298  }
299 
312  ObjectClass* add (std::unique_ptr<ObjectClass> newObject)
313  {
314  return add (newObject.release());
315  }
316 
335  ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject)
336  {
337  const ScopedLockType lock (getLock());
338  values.insert (indexToInsertAt, newObject, 1);
339  return newObject;
340  }
341 
360  ObjectClass* insert (int indexToInsertAt, std::unique_ptr<ObjectClass> newObject)
361  {
362  return insert (indexToInsertAt, newObject.release());
363  }
364 
377  void insertArray (int indexToInsertAt,
378  ObjectClass* const* newObjects,
379  int numberOfElements)
380  {
381  if (numberOfElements > 0)
382  {
383  const ScopedLockType lock (getLock());
384  values.insertArray (indexToInsertAt, newObjects, numberOfElements);
385  }
386  }
387 
401  ObjectClass* set (int indexToChange, ObjectClass* newObject, bool deleteOldElement = true)
402  {
403  if (indexToChange >= 0)
404  {
405  std::unique_ptr<ObjectClass> toDelete;
406 
407  {
408  const ScopedLockType lock (getLock());
409 
410  if (indexToChange < values.size())
411  {
412  if (deleteOldElement)
413  {
414  toDelete.reset (values[indexToChange]);
415 
416  if (toDelete.get() == newObject)
417  toDelete.release();
418  }
419 
420  values[indexToChange] = newObject;
421  }
422  else
423  {
424  values.add (newObject);
425  }
426  }
427  }
428  else
429  {
430  jassertfalse; // you're trying to set an object at a negative index, which doesn't have
431  // any effect - but since the object is not being added, it may be leaking..
432  }
433 
434  return newObject;
435  }
436 
450  ObjectClass* set (int indexToChange, std::unique_ptr<ObjectClass> newObject, bool deleteOldElement = true)
451  {
452  return set (indexToChange, newObject.release(), deleteOldElement);
453  }
454 
464  template <class OtherArrayType>
465  void addArray (const OtherArrayType& arrayToAddFrom,
466  int startIndex = 0,
467  int numElementsToAdd = -1)
468  {
469  const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
470  const ScopedLockType lock2 (getLock());
471  values.addArray (arrayToAddFrom, startIndex, numElementsToAdd);
472  }
473 
475  template <typename OtherArrayType>
476  void addArray (const std::initializer_list<OtherArrayType>& items)
477  {
478  const ScopedLockType lock (getLock());
479  values.addArray (items);
480  }
481 
496  template <class OtherArrayType>
497  void addCopiesOf (const OtherArrayType& arrayToAddFrom,
498  int startIndex = 0,
499  int numElementsToAdd = -1)
500  {
501  const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
502  const ScopedLockType lock2 (getLock());
503 
504  if (startIndex < 0)
505  {
506  jassertfalse;
507  startIndex = 0;
508  }
509 
510  if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
511  numElementsToAdd = arrayToAddFrom.size() - startIndex;
512 
513  jassert (numElementsToAdd >= 0);
514  values.ensureAllocatedSize (values.size() + numElementsToAdd);
515 
516  while (--numElementsToAdd >= 0)
517  values.add (createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++)));
518  }
519 
532  template <class ElementComparator>
533  int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept;
534 
547  template <typename ElementComparator>
548  int indexOfSorted (ElementComparator& comparator, const ObjectClass* objectToLookFor) const noexcept;
549 
550  //==============================================================================
561  void remove (int indexToRemove, bool deleteObject = true)
562  {
563  std::unique_ptr<ObjectClass> toDelete;
564 
565  {
566  const ScopedLockType lock (getLock());
567 
568  if (isPositiveAndBelow (indexToRemove, values.size()))
569  {
570  auto** e = values.begin() + indexToRemove;
571 
572  if (deleteObject)
573  toDelete.reset (*e);
574 
575  values.removeElements (indexToRemove, 1);
576  }
577  }
578 
579  if ((values.size() << 1) < values.capacity())
581  }
582 
592  ObjectClass* removeAndReturn (int indexToRemove)
593  {
594  ObjectClass* removedItem = nullptr;
595  const ScopedLockType lock (getLock());
596 
597  if (isPositiveAndBelow (indexToRemove, values.size()))
598  {
599  removedItem = values[indexToRemove];
600 
601  values.removeElements (indexToRemove, 1);
602 
603  if ((values.size() << 1) < values.capacity())
605  }
606 
607  return removedItem;
608  }
609 
618  void removeObject (const ObjectClass* objectToRemove, bool deleteObject = true)
619  {
620  const ScopedLockType lock (getLock());
621 
622  for (int i = 0; i < values.size(); ++i)
623  {
624  if (objectToRemove == values[i])
625  {
626  remove (i, deleteObject);
627  break;
628  }
629  }
630  }
631 
645  void removeRange (int startIndex, int numberToRemove, bool deleteObjects = true)
646  {
647  const ScopedLockType lock (getLock());
648  auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
649  startIndex = jlimit (0, values.size(), startIndex);
650  numberToRemove = endIndex - startIndex;
651 
652  if (numberToRemove > 0)
653  {
654  Array<ObjectClass*> objectsToDelete;
655 
656  if (deleteObjects)
657  objectsToDelete.addArray (values.begin() + startIndex, numberToRemove);
658 
659  values.removeElements (startIndex, numberToRemove);
660 
661  for (auto& o : objectsToDelete)
663 
664  if ((values.size() << 1) < values.capacity())
666  }
667  }
668 
675  void removeLast (int howManyToRemove = 1,
676  bool deleteObjects = true)
677  {
678  const ScopedLockType lock (getLock());
679 
680  if (howManyToRemove >= values.size())
681  clear (deleteObjects);
682  else
683  removeRange (values.size() - howManyToRemove, howManyToRemove, deleteObjects);
684  }
685 
691  void swap (int index1, int index2) noexcept
692  {
693  const ScopedLockType lock (getLock());
694  values.swap (index1, index2);
695  }
696 
710  void move (int currentIndex, int newIndex) noexcept
711  {
712  if (currentIndex != newIndex)
713  {
714  const ScopedLockType lock (getLock());
715  values.move (currentIndex, newIndex);
716  }
717  }
718 
724  template <class OtherArrayType>
725  void swapWith (OtherArrayType& otherArray) noexcept
726  {
727  const ScopedLockType lock1 (getLock());
728  const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
729  values.swapWith (otherArray.values);
730  }
731 
732  //==============================================================================
739  void minimiseStorageOverheads() noexcept
740  {
741  const ScopedLockType lock (getLock());
742  values.shrinkToNoMoreThan (values.size());
743  }
744 
751  void ensureStorageAllocated (int minNumElements) noexcept
752  {
753  const ScopedLockType lock (getLock());
754  values.ensureAllocatedSize (minNumElements);
755  }
756 
757  //==============================================================================
783  template <class ElementComparator>
784  void sort (ElementComparator& comparator, bool retainOrderOfEquivalentItems = false) noexcept;
785 
786  //==============================================================================
791  inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
792 
794  using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
795 
796  //==============================================================================
797  #ifndef DOXYGEN
798  [[deprecated ("This method has been replaced by a more flexible templated version and renamed "
799  "to swapWith to be more consistent with the names used in other classes.")]]
800  void swapWithArray (OwnedArray& other) noexcept { swapWith (other); }
801  #endif
802 
803 private:
804  //==============================================================================
806 
807  void deleteAllObjects()
808  {
809  auto i = values.size();
810 
811  while (--i >= 0)
812  {
813  auto* e = values[i];
814  values.removeElements (i, 1);
816  }
817  }
818 
819  template <class OtherObjectClass, class OtherCriticalSection>
820  friend class OwnedArray;
821 
822  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
823 };
824 
825 //==============================================================================
826 template <class ObjectClass, class TypeOfCriticalSectionToUse>
827 template <class ElementComparator>
829  [[maybe_unused]] ElementComparator& comparator,
830  ObjectClass* newObject) noexcept
831 {
832  const ScopedLockType lock (getLock());
833  auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
834  insert (index, newObject);
835  return index;
836 }
837 
838 template <class ObjectClass, class TypeOfCriticalSectionToUse>
839 template <typename ElementComparator>
841  [[maybe_unused]] ElementComparator& comparator,
842  const ObjectClass* objectToLookFor) const noexcept
843 {
844  const ScopedLockType lock (getLock());
845  int s = 0, e = values.size();
846 
847  while (s < e)
848  {
849  if (comparator.compareElements (objectToLookFor, values[s]) == 0)
850  return s;
851 
852  auto halfway = (s + e) / 2;
853 
854  if (halfway == s)
855  break;
856 
857  if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
858  s = halfway;
859  else
860  e = halfway;
861  }
862 
863  return -1;
864 }
865 
866 template <class ObjectClass, class TypeOfCriticalSectionToUse>
867 template <typename ElementComparator>
869  [[maybe_unused]] ElementComparator& comparator,
870  bool retainOrderOfEquivalentItems) noexcept
871 {
872  const ScopedLockType lock (getLock());
873 
874  if (size() > 1)
875  sortArray (comparator, values.begin(), 0, size() - 1, retainOrderOfEquivalentItems);
876 }
877 
878 } // namespace juce
void addArray(const Type *elementsToAdd, int numElementsToAdd)
Definition: juce_Array.h:583
int size() const noexcept
ObjectClass * insert(int indexToInsertAt, std::unique_ptr< ObjectClass > newObject)
void addCopiesOf(const OtherArrayType &arrayToAddFrom, int startIndex=0, int numElementsToAdd=-1)
void addArray(const OtherArrayType &arrayToAddFrom, int startIndex=0, int numElementsToAdd=-1)
bool isEmpty() const noexcept
void swapWith(OtherArrayType &otherArray) noexcept
OwnedArray & operator=(OwnedArray &&other) noexcept
void remove(int indexToRemove, bool deleteObject=true)
ObjectClass ** data() noexcept
typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType
void ensureStorageAllocated(int minNumElements) noexcept
ObjectClass *const * begin() const noexcept
void minimiseStorageOverheads() noexcept
void clear(bool deleteObjects=true)
void removeLast(int howManyToRemove=1, bool deleteObjects=true)
int indexOf(const ObjectClass *objectToLookFor) const noexcept
ObjectClass * removeAndReturn(int indexToRemove)
OwnedArray(OwnedArray< OtherObjectClass, OtherCriticalSection > &&other) noexcept
const TypeOfCriticalSectionToUse & getLock() const noexcept
ObjectClass *const * data() const noexcept
void swap(int index1, int index2) noexcept
int indexOfSorted(ElementComparator &comparator, const ObjectClass *objectToLookFor) const noexcept
ObjectClass * getUnchecked(int index) const noexcept
ObjectClass * operator[](int index) const noexcept
void clearQuick(bool deleteObjects)
void removeObject(const ObjectClass *objectToRemove, bool deleteObject=true)
ObjectClass * getLast() const noexcept
ObjectClass * set(int indexToChange, std::unique_ptr< ObjectClass > newObject, bool deleteOldElement=true)
ObjectClass * add(std::unique_ptr< ObjectClass > newObject)
ObjectClass *const * end() const noexcept
OwnedArray()=default
ObjectClass * getFirst() const noexcept
ObjectClass ** end() noexcept
OwnedArray(OwnedArray &&other) noexcept
ObjectClass * insert(int indexToInsertAt, ObjectClass *newObject)
void insertArray(int indexToInsertAt, ObjectClass *const *newObjects, int numberOfElements)
void move(int currentIndex, int newIndex) noexcept
int addSorted(ElementComparator &comparator, ObjectClass *newObject) noexcept
void addArray(const std::initializer_list< OtherArrayType > &items)
ObjectClass ** getRawDataPointer() noexcept
void sort(ElementComparator &comparator, bool retainOrderOfEquivalentItems=false) noexcept
OwnedArray(const std::initializer_list< ObjectClass * > &items)
ObjectClass ** begin() noexcept
void removeRange(int startIndex, int numberToRemove, bool deleteObjects=true)
ObjectClass * set(int indexToChange, ObjectClass *newObject, bool deleteOldElement=true)
ObjectClass * add(ObjectClass *newObject)
bool contains(const ObjectClass *objectToLookFor) const noexcept