OpenShot Audio Library | OpenShotAudio  0.3.2
juce_ReferenceCountedArray.h
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
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,
567  const ObjectClass* objectToLookFor) const noexcept
568  {
569  ignoreUnused (comparator);
570  const ScopedLockType lock (getLock());
571  int s = 0, e = values.size();
572 
573  while (s < e)
574  {
575  if (comparator.compareElements (objectToLookFor, values[s]) == 0)
576  return s;
577 
578  auto halfway = (s + e) / 2;
579 
580  if (halfway == s)
581  break;
582 
583  if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
584  s = halfway;
585  else
586  e = halfway;
587  }
588 
589  return -1;
590  }
591 
592  //==============================================================================
606  void remove (int indexToRemove)
607  {
608  const ScopedLockType lock (getLock());
609 
610  if (isPositiveAndBelow (indexToRemove, values.size()))
611  {
612  auto* e = *(values.begin() + indexToRemove);
613  values.removeElements (indexToRemove, 1);
614  releaseObject (e);
615 
616  if ((values.size() << 1) < values.capacity())
618  }
619  }
620 
630  ObjectClassPtr removeAndReturn (int indexToRemove)
631  {
632  ObjectClassPtr removedItem;
633  const ScopedLockType lock (getLock());
634 
635  if (isPositiveAndBelow (indexToRemove, values.size()))
636  {
637  auto* e = *(values.begin() + indexToRemove);
638  removedItem = e;
639  values.removeElements (indexToRemove, 1);
640  releaseObject (e);
641 
642  if ((values.size() << 1) < values.capacity())
644  }
645 
646  return removedItem;
647  }
648 
657  void removeObject (ObjectClass* objectToRemove)
658  {
659  const ScopedLockType lock (getLock());
660  remove (indexOf (objectToRemove));
661  }
662 
671  void removeObject (const ObjectClassPtr& objectToRemove) { removeObject (objectToRemove.get()); }
672 
688  void removeRange (int startIndex,
689  int numberToRemove)
690  {
691  const ScopedLockType lock (getLock());
692  startIndex = jlimit (0, values.size(), startIndex);
693  auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
694  numberToRemove = endIndex - startIndex;
695 
696  if (numberToRemove > 0)
697  {
698  Array<ObjectClass*> objectsToRemove;
699  objectsToRemove.addArray (values.begin() + startIndex, numberToRemove);
700 
701  values.removeElements (startIndex, numberToRemove);
702 
703  for (auto& o : objectsToRemove)
704  releaseObject (o);
705 
706  if ((values.size() << 1) < values.capacity())
708  }
709  }
710 
719  void removeLast (int howManyToRemove = 1)
720  {
721  const ScopedLockType lock (getLock());
722 
723  if (howManyToRemove > values.size())
724  howManyToRemove = values.size();
725 
726  while (--howManyToRemove >= 0)
727  remove (values.size() - 1);
728  }
729 
735  void swap (int index1, int index2) noexcept
736  {
737  const ScopedLockType lock (getLock());
738 
739  if (isPositiveAndBelow (index1, values.size())
740  && isPositiveAndBelow (index2, values.size()))
741  {
742  std::swap (values[index1], values[index2]);
743  }
744  }
745 
759  void move (int currentIndex, int newIndex) noexcept
760  {
761  if (currentIndex != newIndex)
762  {
763  const ScopedLockType lock (getLock());
764  values.move (currentIndex, newIndex);
765  }
766  }
767 
768  //==============================================================================
774  template <class OtherArrayType>
775  void swapWith (OtherArrayType& otherArray) noexcept
776  {
777  const ScopedLockType lock1 (getLock());
778  const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
779  values.swapWith (otherArray.values);
780  }
781 
782  //==============================================================================
787  bool operator== (const ReferenceCountedArray& other) const noexcept
788  {
789  const ScopedLockType lock2 (other.getLock());
790  const ScopedLockType lock1 (getLock());
791  return values == other.values;
792  }
793 
799  {
800  return ! operator== (other);
801  }
802 
803  //==============================================================================
830  template <class ElementComparator>
831  void sort (ElementComparator& comparator,
832  bool retainOrderOfEquivalentItems = false) noexcept
833  {
834  // If you pass in an object with a static compareElements() method, this
835  // avoids getting warning messages about the parameter being unused
836  ignoreUnused (comparator);
837 
838  const ScopedLockType lock (getLock());
839  sortArray (comparator, values.begin(), 0, values.size() - 1, retainOrderOfEquivalentItems);
840  }
841 
842  //==============================================================================
849  void minimiseStorageOverheads() noexcept
850  {
851  const ScopedLockType lock (getLock());
852  values.shrinkToNoMoreThan (values.size());
853  }
854 
861  void ensureStorageAllocated (const int minNumElements)
862  {
863  const ScopedLockType lock (getLock());
864  values.ensureAllocatedSize (minNumElements);
865  }
866 
867  //==============================================================================
872  inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return values; }
873 
875  using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
876 
877  //==============================================================================
878  #ifndef DOXYGEN
879  // Note that the swapWithArray method has been replaced by a more flexible templated version,
880  // and renamed "swapWith" to be more consistent with the names used in other classes.
881  JUCE_DEPRECATED_WITH_BODY (void swapWithArray (ReferenceCountedArray& other) noexcept, { swapWith (other); })
882  #endif
883 
884 private:
885  //==============================================================================
887 
888  void releaseAllObjects()
889  {
890  auto i = values.size();
891 
892  while (--i >= 0)
893  {
894  auto* e = values[i];
895  values.removeElements (i, 1);
896  releaseObject (e);
897  }
898  }
899 
900  static void releaseObject (ObjectClass* o)
901  {
902  if (o != nullptr && o->decReferenceCountWithoutDeleting())
903  ContainerDeletePolicy<ObjectClass>::destroy (o);
904  }
905 };
906 
907 } // 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