OpenShot Audio Library | OpenShotAudio  0.6.0
juce_ReferenceCountedArray.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 //==============================================================================
49 template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
51 {
52 public:
54 
55  //==============================================================================
59  ReferenceCountedArray() = default;
60 
63  {
64  const ScopedLockType lock (other.getLock());
65  values.addArray (other.begin(), other.size());
66 
67  for (auto* o : *this)
68  if (o != nullptr)
69  o->incReferenceCount();
70  }
71 
74  : values (std::move (other.values))
75  {
76  }
77 
79  template <class OtherObjectClass, class OtherCriticalSection>
81  {
83  values.addArray (other.begin(), other.size());
84 
85  for (auto* o : *this)
86  if (o != nullptr)
87  o->incReferenceCount();
88  }
89 
94  {
95  releaseAllObjects();
96  auto otherCopy = other;
97  swapWith (otherCopy);
98  return *this;
99  }
100 
104  template <class OtherObjectClass>
106  {
107  auto otherCopy = other;
108  swapWith (otherCopy);
109  return *this;
110  }
111 
114  {
115  releaseAllObjects();
116  values = std::move (other.values);
117  return *this;
118  }
119 
124  {
125  releaseAllObjects();
126  }
127 
128  //==============================================================================
132  void clear()
133  {
134  const ScopedLockType lock (getLock());
135  clearQuick();
136  values.setAllocatedSize (0);
137  }
138 
143  void clearQuick()
144  {
145  const ScopedLockType lock (getLock());
146  releaseAllObjects();
147  }
148 
150  inline int size() const noexcept
151  {
152  return values.size();
153  }
154 
156  inline bool isEmpty() const noexcept
157  {
158  return size() == 0;
159  }
160 
169  inline ObjectClassPtr operator[] (int index) const noexcept
170  {
171  return ObjectClassPtr (getObjectPointer (index));
172  }
173 
180  inline ObjectClassPtr getUnchecked (int index) const noexcept
181  {
182  return ObjectClassPtr (getObjectPointerUnchecked (index));
183  }
184 
193  inline ObjectClass* getObjectPointer (int index) const noexcept
194  {
195  const ScopedLockType lock (getLock());
196  return values.getValueWithDefault (index);
197  }
198 
202  inline ObjectClass* getObjectPointerUnchecked (int index) const noexcept
203  {
204  const ScopedLockType lock (getLock());
205  return values[index];
206  }
207 
213  inline ObjectClassPtr getFirst() const noexcept
214  {
215  const ScopedLockType lock (getLock());
216  return values.getFirst();
217  }
218 
224  inline ObjectClassPtr getLast() const noexcept
225  {
226  const ScopedLockType lock (getLock());
227  return values.getLast();
228  }
229 
234  inline ObjectClass** getRawDataPointer() const noexcept
235  {
236  return values.begin();
237  }
238 
239  //==============================================================================
243  inline ObjectClass** begin() noexcept
244  {
245  return values.begin();
246  }
247 
251  inline ObjectClass* const* begin() const noexcept
252  {
253  return values.begin();
254  }
255 
259  inline ObjectClass** end() noexcept
260  {
261  return values.end();
262  }
263 
267  inline ObjectClass* const* end() const noexcept
268  {
269  return values.end();
270  }
271 
275  inline ObjectClass** data() noexcept
276  {
277  return begin();
278  }
279 
283  inline ObjectClass* const* data() const noexcept
284  {
285  return begin();
286  }
287 
288  //==============================================================================
294  int indexOf (const ObjectClass* objectToLookFor) const noexcept
295  {
296  const ScopedLockType lock (getLock());
297  auto* e = values.begin();
298  auto* endPointer = values.end();
299 
300  while (e != endPointer)
301  {
302  if (objectToLookFor == *e)
303  return static_cast<int> (e - values.begin());
304 
305  ++e;
306  }
307 
308  return -1;
309  }
310 
316  int indexOf (const ObjectClassPtr& objectToLookFor) const noexcept { return indexOf (objectToLookFor.get()); }
317 
323  bool contains (const ObjectClass* objectToLookFor) const noexcept
324  {
325  const ScopedLockType lock (getLock());
326  auto* e = values.begin();
327  auto* endPointer = values.end();
328 
329  while (e != endPointer)
330  {
331  if (objectToLookFor == *e)
332  return true;
333 
334  ++e;
335  }
336 
337  return false;
338  }
339 
345  bool contains (const ObjectClassPtr& objectToLookFor) const noexcept { return contains (objectToLookFor.get()); }
346 
354  ObjectClass* add (ObjectClass* newObject)
355  {
356  const ScopedLockType lock (getLock());
357  values.add (newObject);
358 
359  if (newObject != nullptr)
360  newObject->incReferenceCount();
361 
362  return newObject;
363  }
364 
372  ObjectClass* add (const ObjectClassPtr& newObject) { return add (newObject.get()); }
373 
387  ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject)
388  {
389  values.insert (indexToInsertAt, newObject, 1);
390 
391  if (newObject != nullptr)
392  newObject->incReferenceCount();
393 
394  return newObject;
395  }
396 
410  ObjectClass* insert (int indexToInsertAt, const ObjectClassPtr& newObject) { return insert (indexToInsertAt, newObject.get()); }
411 
420  bool addIfNotAlreadyThere (ObjectClass* newObject)
421  {
422  const ScopedLockType lock (getLock());
423 
424  if (contains (newObject))
425  return false;
426 
427  add (newObject);
428  return true;
429  }
430 
439  bool addIfNotAlreadyThere (const ObjectClassPtr& newObject) { return addIfNotAlreadyThere (newObject.get()); }
440 
453  void set (int indexToChange, ObjectClass* newObject)
454  {
455  if (indexToChange >= 0)
456  {
457  const ScopedLockType lock (getLock());
458 
459  if (newObject != nullptr)
460  newObject->incReferenceCount();
461 
462  if (indexToChange < values.size())
463  {
464  auto* e = values[indexToChange];
465  values[indexToChange] = newObject;
466  releaseObject (e);
467  }
468  else
469  {
470  values.add (newObject);
471  }
472  }
473  }
474 
487  void set (int indexToChange, const ObjectClassPtr& newObject) { set (indexToChange, newObject.get()); }
488 
498  void addArray (const ReferenceCountedArray& arrayToAddFrom,
499  int startIndex = 0,
500  int numElementsToAdd = -1) noexcept
501  {
502  const ScopedLockType lock1 (arrayToAddFrom.getLock());
503 
504  {
505  const ScopedLockType lock2 (getLock());
506 
507  auto numElementsAdded = values.addArray (arrayToAddFrom.values, startIndex, numElementsToAdd);
508  auto** e = values.end();
509 
510  for (int i = 0; i < numElementsAdded; ++i)
511  (*(--e))->incReferenceCount();
512  }
513  }
514 
527  template <class ElementComparator>
528  int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
529  {
530  const ScopedLockType lock (getLock());
531  auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
532  insert (index, newObject);
533  return index;
534  }
535 
541  template <class ElementComparator>
542  void addOrReplaceSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
543  {
544  const ScopedLockType lock (getLock());
545  auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
546 
547  if (index > 0 && comparator.compareElements (newObject, values[index - 1]) == 0)
548  set (index - 1, newObject); // replace an existing object that matches
549  else
550  insert (index, newObject); // no match, so insert the new one
551  }
552 
565  template <class ElementComparator>
566  int indexOfSorted (ElementComparator& comparator, const ObjectClass* objectToLookFor) const noexcept;
567 
568  //==============================================================================
582  void remove (int indexToRemove)
583  {
584  const ScopedLockType lock (getLock());
585 
586  if (isPositiveAndBelow (indexToRemove, values.size()))
587  {
588  auto* e = *(values.begin() + indexToRemove);
589  values.removeElements (indexToRemove, 1);
590  releaseObject (e);
591 
592  if ((values.size() << 1) < values.capacity())
594  }
595  }
596 
606  ObjectClassPtr removeAndReturn (int indexToRemove)
607  {
608  ObjectClassPtr removedItem;
609  const ScopedLockType lock (getLock());
610 
611  if (isPositiveAndBelow (indexToRemove, values.size()))
612  {
613  auto* e = *(values.begin() + indexToRemove);
614  removedItem = e;
615  values.removeElements (indexToRemove, 1);
616  releaseObject (e);
617 
618  if ((values.size() << 1) < values.capacity())
620  }
621 
622  return removedItem;
623  }
624 
633  void removeObject (ObjectClass* objectToRemove)
634  {
635  const ScopedLockType lock (getLock());
636  remove (indexOf (objectToRemove));
637  }
638 
647  void removeObject (const ObjectClassPtr& objectToRemove) { removeObject (objectToRemove.get()); }
648 
664  void removeRange (int startIndex,
665  int numberToRemove)
666  {
667  const ScopedLockType lock (getLock());
668  startIndex = jlimit (0, values.size(), startIndex);
669  auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
670  numberToRemove = endIndex - startIndex;
671 
672  if (numberToRemove > 0)
673  {
674  Array<ObjectClass*> objectsToRemove;
675  objectsToRemove.addArray (values.begin() + startIndex, numberToRemove);
676 
677  values.removeElements (startIndex, numberToRemove);
678 
679  for (auto& o : objectsToRemove)
680  releaseObject (o);
681 
682  if ((values.size() << 1) < values.capacity())
684  }
685  }
686 
695  void removeLast (int howManyToRemove = 1)
696  {
697  const ScopedLockType lock (getLock());
698 
699  if (howManyToRemove > values.size())
700  howManyToRemove = values.size();
701 
702  while (--howManyToRemove >= 0)
703  remove (values.size() - 1);
704  }
705 
711  void swap (int index1, int index2) noexcept
712  {
713  const ScopedLockType lock (getLock());
714 
715  if (isPositiveAndBelow (index1, values.size())
716  && isPositiveAndBelow (index2, values.size()))
717  {
718  std::swap (values[index1], values[index2]);
719  }
720  }
721 
735  void move (int currentIndex, int newIndex) noexcept
736  {
737  if (currentIndex != newIndex)
738  {
739  const ScopedLockType lock (getLock());
740  values.move (currentIndex, newIndex);
741  }
742  }
743 
744  //==============================================================================
750  template <class OtherArrayType>
751  void swapWith (OtherArrayType& otherArray) noexcept
752  {
753  const ScopedLockType lock1 (getLock());
754  const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
755  values.swapWith (otherArray.values);
756  }
757 
758  //==============================================================================
763  bool operator== (const ReferenceCountedArray& other) const noexcept
764  {
765  const ScopedLockType lock2 (other.getLock());
766  const ScopedLockType lock1 (getLock());
767  return values == other.values;
768  }
769 
775  {
776  return ! operator== (other);
777  }
778 
779  //==============================================================================
806  template <class ElementComparator>
807  void sort (ElementComparator& comparator, bool retainOrderOfEquivalentItems = false) noexcept;
808 
809  //==============================================================================
816  void minimiseStorageOverheads() noexcept
817  {
818  const ScopedLockType lock (getLock());
819  values.shrinkToNoMoreThan (values.size());
820  }
821 
828  void ensureStorageAllocated (const int minNumElements)
829  {
830  const ScopedLockType lock (getLock());
831  values.ensureAllocatedSize (minNumElements);
832  }
833 
834  //==============================================================================
839  inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
840 
842  using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
843 
844  //==============================================================================
845  #ifndef DOXYGEN
846  [[deprecated ("This method has been replaced by a more flexible templated version and renamed "
847  "to swapWith to be more consistent with the names used in other classes.")]]
848  void swapWithArray (ReferenceCountedArray& other) noexcept { swapWith (other); }
849  #endif
850 
851 private:
852  //==============================================================================
854 
855  void releaseAllObjects()
856  {
857  auto i = values.size();
858 
859  while (--i >= 0)
860  {
861  auto* e = values[i];
862  values.removeElements (i, 1);
863  releaseObject (e);
864  }
865  }
866 
867  static void releaseObject (ObjectClass* o)
868  {
869  if (o != nullptr && o->decReferenceCountWithoutDeleting())
870  ContainerDeletePolicy<ObjectClass>::destroy (o);
871  }
872 };
873 
874 //==============================================================================
875 template <class ObjectClass, class TypeOfCriticalSectionToUse>
876 template <class ElementComparator>
878  [[maybe_unused]] ElementComparator& comparator,
879  const ObjectClass* objectToLookFor) const noexcept
880 {
881  const ScopedLockType lock (getLock());
882  int s = 0, e = values.size();
883 
884  while (s < e)
885  {
886  if (comparator.compareElements (objectToLookFor, values[s]) == 0)
887  return s;
888 
889  auto halfway = (s + e) / 2;
890 
891  if (halfway == s)
892  break;
893 
894  if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
895  s = halfway;
896  else
897  e = halfway;
898  }
899 
900  return -1;
901 }
902 
903 template <class ObjectClass, class TypeOfCriticalSectionToUse>
904 template <class ElementComparator>
906  [[maybe_unused]] ElementComparator& comparator,
907  bool retainOrderOfEquivalentItems) noexcept
908 {
909  const ScopedLockType lock (getLock());
910  sortArray (comparator, values.begin(), 0, values.size() - 1, retainOrderOfEquivalentItems);
911 }
912 
913 } // namespace juce
void addArray(const Type *elementsToAdd, int numElementsToAdd)
Definition: juce_Array.h:583
ReferenceCountedArray(ReferenceCountedArray &&other) noexcept
ObjectClass *const * end() const noexcept
int indexOf(const ObjectClass *objectToLookFor) const noexcept
ReferenceCountedArray(const ReferenceCountedArray &other) noexcept
void removeLast(int howManyToRemove=1)
void set(int indexToChange, ObjectClass *newObject)
ObjectClass *const * begin() const noexcept
ObjectClass * add(ObjectClass *newObject)
ObjectClass * add(const ObjectClassPtr &newObject)
bool operator!=(const ReferenceCountedArray< ObjectClass, TypeOfCriticalSectionToUse > &other) const noexcept
const TypeOfCriticalSectionToUse & getLock() const noexcept
int indexOfSorted(ElementComparator &comparator, const ObjectClass *objectToLookFor) const noexcept
typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType
bool addIfNotAlreadyThere(ObjectClass *newObject)
ObjectClassPtr operator[](int index) const noexcept
void sort(ElementComparator &comparator, bool retainOrderOfEquivalentItems=false) noexcept
ReferenceCountedArray(const ReferenceCountedArray< OtherObjectClass, OtherCriticalSection > &other) noexcept
ObjectClass ** getRawDataPointer() const noexcept
bool operator==(const ReferenceCountedArray &other) const noexcept
void removeObject(ObjectClass *objectToRemove)
ObjectClass * getObjectPointerUnchecked(int index) const noexcept
ObjectClass * getObjectPointer(int index) const noexcept
void swap(int index1, int index2) noexcept
ObjectClassPtr getFirst() const noexcept
void ensureStorageAllocated(const int minNumElements)
void set(int indexToChange, const ObjectClassPtr &newObject)
ObjectClassPtr getUnchecked(int index) const noexcept
void addOrReplaceSorted(ElementComparator &comparator, ObjectClass *newObject) noexcept
bool contains(const ObjectClass *objectToLookFor) const noexcept
void removeRange(int startIndex, int numberToRemove)
void move(int currentIndex, int newIndex) noexcept
ObjectClassPtr removeAndReturn(int indexToRemove)
bool contains(const ObjectClassPtr &objectToLookFor) const noexcept
ObjectClass * insert(int indexToInsertAt, ObjectClass *newObject)
ObjectClass * insert(int indexToInsertAt, const ObjectClassPtr &newObject)
void swapWith(OtherArrayType &otherArray) noexcept
bool addIfNotAlreadyThere(const ObjectClassPtr &newObject)
ReferenceCountedArray & operator=(const ReferenceCountedArray &other) noexcept
int addSorted(ElementComparator &comparator, ObjectClass *newObject) noexcept
int indexOf(const ObjectClassPtr &objectToLookFor) const noexcept
ObjectClassPtr getLast() const noexcept
void addArray(const ReferenceCountedArray &arrayToAddFrom, int startIndex=0, int numElementsToAdd=-1) noexcept
ObjectClass *const * data() const noexcept
void removeObject(const ObjectClassPtr &objectToRemove)
ReferencedType * get() const noexcept