| @@ -64,19 +64,15 @@ public: | |||
| //============================================================================== | |||
| /** Creates an empty set. */ | |||
| SortedSet() noexcept | |||
| : numUsed (0) | |||
| { | |||
| } | |||
| /** Creates a copy of another set. | |||
| @param other the set to copy | |||
| */ | |||
| SortedSet (const SortedSet& other) noexcept | |||
| SortedSet (const SortedSet& other) | |||
| : data (other.data) | |||
| { | |||
| const ScopedLockType lock (other.getLock()); | |||
| numUsed = other.numUsed; | |||
| data.setAllocatedSize (other.numUsed); | |||
| memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); | |||
| } | |||
| /** Destructor. */ | |||
| @@ -89,47 +85,22 @@ public: | |||
| */ | |||
| SortedSet& operator= (const SortedSet& other) noexcept | |||
| { | |||
| if (this != &other) | |||
| { | |||
| const ScopedLockType lock1 (other.getLock()); | |||
| const ScopedLockType lock2 (getLock()); | |||
| data.ensureAllocatedSize (other.size()); | |||
| numUsed = other.numUsed; | |||
| memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); | |||
| minimiseStorageOverheads(); | |||
| } | |||
| data = other.data; | |||
| return *this; | |||
| } | |||
| //============================================================================== | |||
| /** Compares this set to another one. | |||
| Two sets are considered equal if they both contain the same set of | |||
| elements. | |||
| Two sets are considered equal if they both contain the same set of elements. | |||
| @param other the other set to compare with | |||
| */ | |||
| bool operator== (const SortedSet<ElementType>& other) const noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| if (numUsed != other.numUsed) | |||
| return false; | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (! (data.elements[i] == other.data.elements[i])) | |||
| return false; | |||
| return true; | |||
| return data == other.data; | |||
| } | |||
| /** Compares this set to another one. | |||
| Two sets are considered equal if they both contain the same set of | |||
| elements. | |||
| Two sets are considered equal if they both contain the same set of elements. | |||
| @param other the other set to compare with | |||
| */ | |||
| bool operator!= (const SortedSet<ElementType>& other) const noexcept | |||
| @@ -148,9 +119,7 @@ public: | |||
| */ | |||
| void clear() noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| data.setAllocatedSize (0); | |||
| numUsed = 0; | |||
| data.clear(); | |||
| } | |||
| /** Removes all elements from the set without freeing the array's allocated storage. | |||
| @@ -159,8 +128,7 @@ public: | |||
| */ | |||
| void clearQuick() noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| numUsed = 0; | |||
| data.clearQuick(); | |||
| } | |||
| //============================================================================== | |||
| @@ -168,7 +136,7 @@ public: | |||
| */ | |||
| inline int size() const noexcept | |||
| { | |||
| return numUsed; | |||
| return data.size(); | |||
| } | |||
| /** Returns one of the elements in the set. | |||
| @@ -184,9 +152,7 @@ public: | |||
| */ | |||
| inline ElementType operator[] (const int index) const noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| return isPositiveAndBelow (index, numUsed) ? data.elements [index] | |||
| : ElementType(); | |||
| return data [index]; | |||
| } | |||
| /** Returns one of the elements in the set, without checking the index passed in. | |||
| @@ -199,9 +165,7 @@ public: | |||
| */ | |||
| inline ElementType getUnchecked (const int index) const noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (isPositiveAndBelow (index, numUsed)); | |||
| return data.elements [index]; | |||
| return data.getUnchecked (index); | |||
| } | |||
| /** Returns a direct reference to one of the elements in the set, without checking the index passed in. | |||
| @@ -214,9 +178,7 @@ public: | |||
| */ | |||
| inline ElementType& getReference (const int index) const noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| jassert (isPositiveAndBelow (index, numUsed)); | |||
| return data.elements [index]; | |||
| return data.getReference (index); | |||
| } | |||
| /** Returns the first element in the set, or 0 if the set is empty. | |||
| @@ -225,8 +187,7 @@ public: | |||
| */ | |||
| inline ElementType getFirst() const noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [0] : ElementType(); | |||
| return data.getFirst(); | |||
| } | |||
| /** Returns the last element in the set, or 0 if the set is empty. | |||
| @@ -235,8 +196,7 @@ public: | |||
| */ | |||
| inline ElementType getLast() const noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| return numUsed > 0 ? data.elements [numUsed - 1] : ElementType(); | |||
| return data.getLast(); | |||
| } | |||
| //============================================================================== | |||
| @@ -245,7 +205,7 @@ public: | |||
| */ | |||
| inline ElementType* begin() const noexcept | |||
| { | |||
| return data.elements; | |||
| return data.begin(); | |||
| } | |||
| /** Returns a pointer to the element which follows the last element in the set. | |||
| @@ -253,7 +213,7 @@ public: | |||
| */ | |||
| inline ElementType* end() const noexcept | |||
| { | |||
| return data.elements + numUsed; | |||
| return data.end(); | |||
| } | |||
| //============================================================================== | |||
| @@ -267,32 +227,27 @@ public: | |||
| */ | |||
| int indexOf (const ElementType elementToLookFor) const noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| const ScopedLockType lock (data.getLock()); | |||
| int start = 0; | |||
| int end_ = numUsed; | |||
| int end_ = data.size(); | |||
| for (;;) | |||
| { | |||
| if (start >= end_) | |||
| { | |||
| return -1; | |||
| } | |||
| else if (elementToLookFor == data.elements [start]) | |||
| { | |||
| if (elementToLookFor == data.getReference (start)) | |||
| return start; | |||
| } | |||
| else | |||
| { | |||
| const int halfway = (start + end_) >> 1; | |||
| if (halfway == start) | |||
| return -1; | |||
| else if (elementToLookFor < data.elements [halfway]) | |||
| end_ = halfway; | |||
| else | |||
| start = halfway; | |||
| } | |||
| const int halfway = (start + end_) >> 1; | |||
| if (halfway == start) | |||
| return -1; | |||
| else if (elementToLookFor < data.getReference (halfway)) | |||
| end_ = halfway; | |||
| else | |||
| start = halfway; | |||
| } | |||
| } | |||
| @@ -306,29 +261,24 @@ public: | |||
| const ScopedLockType lock (getLock()); | |||
| int start = 0; | |||
| int end_ = numUsed; | |||
| int end_ = data.size(); | |||
| for (;;) | |||
| { | |||
| if (start >= end_) | |||
| { | |||
| return false; | |||
| } | |||
| else if (elementToLookFor == data.elements [start]) | |||
| { | |||
| if (elementToLookFor == data.getReference (start)) | |||
| return true; | |||
| } | |||
| else | |||
| { | |||
| const int halfway = (start + end_) >> 1; | |||
| if (halfway == start) | |||
| return false; | |||
| else if (elementToLookFor < data.elements [halfway]) | |||
| end_ = halfway; | |||
| else | |||
| start = halfway; | |||
| } | |||
| const int halfway = (start + end_) >> 1; | |||
| if (halfway == start) | |||
| return false; | |||
| else if (elementToLookFor < data.getReference (halfway)) | |||
| end_ = halfway; | |||
| else | |||
| start = halfway; | |||
| } | |||
| } | |||
| @@ -343,38 +293,35 @@ public: | |||
| const ScopedLockType lock (getLock()); | |||
| int start = 0; | |||
| int end_ = numUsed; | |||
| int end_ = data.size(); | |||
| for (;;) | |||
| { | |||
| if (start >= end_) | |||
| { | |||
| jassert (start <= end_); | |||
| insertInternal (start, newElement); | |||
| data.insert (start, newElement); | |||
| break; | |||
| } | |||
| else if (newElement == data.elements [start]) | |||
| { | |||
| if (newElement == data.getReference (start)) | |||
| break; | |||
| } | |||
| else | |||
| { | |||
| const int halfway = (start + end_) >> 1; | |||
| if (halfway == start) | |||
| { | |||
| if (newElement < data.elements [halfway]) | |||
| insertInternal (start, newElement); | |||
| else | |||
| insertInternal (start + 1, newElement); | |||
| const int halfway = (start + end_) >> 1; | |||
| break; | |||
| } | |||
| else if (newElement < data.elements [halfway]) | |||
| end_ = halfway; | |||
| if (halfway == start) | |||
| { | |||
| if (newElement < data.getReference (halfway)) | |||
| data.insert (start, newElement); | |||
| else | |||
| start = halfway; | |||
| data.insert (start + 1, newElement); | |||
| break; | |||
| } | |||
| else if (newElement < data.getReference (halfway)) | |||
| end_ = halfway; | |||
| else | |||
| start = halfway; | |||
| } | |||
| } | |||
| @@ -424,12 +371,12 @@ public: | |||
| if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size()) | |||
| numElementsToAdd = setToAddFrom.size() - startIndex; | |||
| addArray (setToAddFrom.data.elements + startIndex, numElementsToAdd); | |||
| if (numElementsToAdd > 0) | |||
| addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd); | |||
| } | |||
| } | |||
| } | |||
| //============================================================================== | |||
| /** Removes an element from the set. | |||
| @@ -442,26 +389,7 @@ public: | |||
| */ | |||
| ElementType remove (const int indexToRemove) noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| if (isPositiveAndBelow (indexToRemove, numUsed)) | |||
| { | |||
| --numUsed; | |||
| ElementType* const e = data.elements + indexToRemove; | |||
| ElementType const removed = *e; | |||
| const int numberToShift = numUsed - indexToRemove; | |||
| if (numberToShift > 0) | |||
| memmove (e, e + 1, sizeof (ElementType) * (size_t) numberToShift); | |||
| if ((numUsed << 1) < data.numAllocated) | |||
| minimiseStorageOverheads(); | |||
| return removed; | |||
| } | |||
| return ElementType(); | |||
| return data.remove (indexToRemove); | |||
| } | |||
| /** Removes an item from the set. | |||
| @@ -474,7 +402,7 @@ public: | |||
| void removeValue (const ElementType valueToRemove) noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| remove (indexOf (valueToRemove)); | |||
| data.remove (indexOf (valueToRemove)); | |||
| } | |||
| /** Removes any elements which are also in another set. | |||
| @@ -492,14 +420,11 @@ public: | |||
| { | |||
| clear(); | |||
| } | |||
| else | |||
| else if (otherSet.size() > 0) | |||
| { | |||
| if (otherSet.size() > 0) | |||
| { | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (otherSet.contains (data.elements [i])) | |||
| remove (i); | |||
| } | |||
| for (int i = data.size(); --i >= 0;) | |||
| if (otherSet.contains (data.getReference (i))) | |||
| remove (i); | |||
| } | |||
| } | |||
| @@ -524,8 +449,8 @@ public: | |||
| } | |||
| else | |||
| { | |||
| for (int i = numUsed; --i >= 0;) | |||
| if (! otherSet.contains (data.elements [i])) | |||
| for (int i = data.size(); --i >= 0;) | |||
| if (! otherSet.contains (data.getReference (i))) | |||
| remove (i); | |||
| } | |||
| } | |||
| @@ -538,11 +463,7 @@ public: | |||
| */ | |||
| void swapWith (SortedSet& otherSet) noexcept | |||
| { | |||
| const ScopedLockType lock1 (getLock()); | |||
| const ScopedLockType lock2 (otherSet.getLock()); | |||
| data.swapWith (otherSet.data); | |||
| swapVariables (numUsed, otherSet.numUsed); | |||
| data.swapWithArray (otherSet.data); | |||
| } | |||
| //============================================================================== | |||
| @@ -554,8 +475,7 @@ public: | |||
| */ | |||
| void minimiseStorageOverheads() noexcept | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| data.shrinkToNoMoreThan (numUsed); | |||
| data.minimiseStorageOverheads(); | |||
| } | |||
| /** Increases the set's internal storage to hold a minimum number of elements. | |||
| @@ -566,8 +486,7 @@ public: | |||
| */ | |||
| void ensureStorageAllocated (const int minNumElements) | |||
| { | |||
| const ScopedLockType lock (getLock()); | |||
| data.ensureAllocatedSize (minNumElements); | |||
| data.ensureStorageAllocated (minNumElements); | |||
| } | |||
| //============================================================================== | |||
| @@ -575,7 +494,7 @@ public: | |||
| To lock, you can call getLock().enter() and getLock().exit(), or preferably use | |||
| an object of ScopedLockType as an RAII lock for it. | |||
| */ | |||
| inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; } | |||
| inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data.getLock(); } | |||
| /** Returns the type of scoped lock to use for locking this array */ | |||
| typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; | |||
| @@ -583,22 +502,7 @@ public: | |||
| private: | |||
| //============================================================================== | |||
| ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse> data; | |||
| int numUsed; | |||
| void insertInternal (const int indexToInsertAt, const ElementType newElement) noexcept | |||
| { | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| ElementType* const insertPos = data.elements + indexToInsertAt; | |||
| const int numberToMove = numUsed - indexToInsertAt; | |||
| if (numberToMove > 0) | |||
| memmove (insertPos + 1, insertPos, sizeof (ElementType) * (size_t) numberToMove); | |||
| new (insertPos) ElementType (newElement); | |||
| ++numUsed; | |||
| } | |||
| Array <ElementType, TypeOfCriticalSectionToUse> data; | |||
| }; | |||
| #if JUCE_MSVC | |||