| @@ -679,30 +679,23 @@ public: | |||||
| // avoids getting warning messages about the parameter being unused | // avoids getting warning messages about the parameter being unused | ||||
| const ScopedLockType lock (getLock()); | const ScopedLockType lock (getLock()); | ||||
| int start = 0; | |||||
| int end_ = numUsed; | |||||
| for (;;) | |||||
| for (int s = 0, e = numUsed;;) | |||||
| { | { | ||||
| if (start >= end_) | |||||
| { | |||||
| if (s >= e) | |||||
| return -1; | return -1; | ||||
| } | |||||
| else if (comparator.compareElements (elementToLookFor, data.elements [start]) == 0) | |||||
| { | |||||
| return start; | |||||
| } | |||||
| else | |||||
| { | |||||
| const int halfway = (start + end_) >> 1; | |||||
| if (halfway == start) | |||||
| return -1; | |||||
| else if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0) | |||||
| start = halfway; | |||||
| else | |||||
| end_ = halfway; | |||||
| } | |||||
| if (comparator.compareElements (elementToLookFor, data.elements [s]) == 0) | |||||
| return s; | |||||
| const int halfway = (s + e) / 2; | |||||
| if (halfway == s) | |||||
| return -1; | |||||
| if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0) | |||||
| s = halfway; | |||||
| else | |||||
| e = halfway; | |||||
| } | } | ||||
| } | } | ||||
| @@ -733,9 +726,7 @@ public: | |||||
| if (numberToShift > 0) | if (numberToShift > 0) | ||||
| memmove (e, e + 1, ((size_t) numberToShift) * sizeof (ElementType)); | memmove (e, e + 1, ((size_t) numberToShift) * sizeof (ElementType)); | ||||
| if ((numUsed << 1) < data.numAllocated) | |||||
| minimiseStorageOverheads(); | |||||
| minimiseStorageAfterRemoval(); | |||||
| return removed; | return removed; | ||||
| } | } | ||||
| else | else | ||||
| @@ -798,9 +789,7 @@ public: | |||||
| memmove (e, e + numberToRemove, ((size_t) numToShift) * sizeof (ElementType)); | memmove (e, e + numberToRemove, ((size_t) numToShift) * sizeof (ElementType)); | ||||
| numUsed -= numberToRemove; | numUsed -= numberToRemove; | ||||
| if ((numUsed << 1) < data.numAllocated) | |||||
| minimiseStorageOverheads(); | |||||
| minimiseStorageAfterRemoval(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -820,9 +809,7 @@ public: | |||||
| data.elements [numUsed - i].~ElementType(); | data.elements [numUsed - i].~ElementType(); | ||||
| numUsed -= howManyToRemove; | numUsed -= howManyToRemove; | ||||
| if ((numUsed << 1) < data.numAllocated) | |||||
| minimiseStorageOverheads(); | |||||
| minimiseStorageAfterRemoval(); | |||||
| } | } | ||||
| /** Removes any elements which are also in another array. | /** Removes any elements which are also in another array. | ||||
| @@ -1029,6 +1016,12 @@ private: | |||||
| for (int i = 0; i < numUsed; ++i) | for (int i = 0; i < numUsed; ++i) | ||||
| data.elements[i].~ElementType(); | data.elements[i].~ElementType(); | ||||
| } | } | ||||
| void minimiseStorageAfterRemoval() | |||||
| { | |||||
| if (data.numAllocated > numUsed * 2) | |||||
| data.shrinkToNoMoreThan (jmax (numUsed, 64 / (int) sizeof (ElementType))); | |||||
| } | |||||
| }; | }; | ||||
| @@ -45,27 +45,22 @@ void ReadWriteLock::enterRead() const noexcept | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| jassert (readerThreads.size() % 2 == 0); | |||||
| int i; | |||||
| for (i = 0; i < readerThreads.size(); i += 2) | |||||
| if (readerThreads.getUnchecked(i) == threadId) | |||||
| break; | |||||
| if (i < readerThreads.size() | |||||
| || numWriters + numWaitingWriters == 0 | |||||
| || (threadId == writerThreadId && numWriters > 0)) | |||||
| for (int i = 0; i < readerThreads.size(); ++i) | |||||
| { | { | ||||
| if (i < readerThreads.size()) | |||||
| { | |||||
| readerThreads.set (i + 1, (Thread::ThreadID) (1 + (pointer_sized_int) readerThreads.getUnchecked (i + 1))); | |||||
| } | |||||
| else | |||||
| ThreadRecursionCount& trc = readerThreads.getReference(i); | |||||
| if (trc.threadID == threadId) | |||||
| { | { | ||||
| readerThreads.add (threadId); | |||||
| readerThreads.add ((Thread::ThreadID) 1); | |||||
| trc.count++; | |||||
| return; | |||||
| } | } | ||||
| } | |||||
| if (numWriters + numWaitingWriters == 0 | |||||
| || (threadId == writerThreadId && numWriters > 0)) | |||||
| { | |||||
| ThreadRecursionCount trc = { threadId, 1 }; | |||||
| readerThreads.add (trc); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -79,21 +74,17 @@ void ReadWriteLock::exitRead() const noexcept | |||||
| const Thread::ThreadID threadId = Thread::getCurrentThreadId(); | const Thread::ThreadID threadId = Thread::getCurrentThreadId(); | ||||
| const SpinLock::ScopedLockType sl (accessLock); | const SpinLock::ScopedLockType sl (accessLock); | ||||
| for (int i = 0; i < readerThreads.size(); i += 2) | |||||
| for (int i = 0; i < readerThreads.size(); ++i) | |||||
| { | { | ||||
| if (readerThreads.getUnchecked(i) == threadId) | |||||
| { | |||||
| const pointer_sized_int newCount = ((pointer_sized_int) readerThreads.getUnchecked (i + 1)) - 1; | |||||
| ThreadRecursionCount& trc = readerThreads.getReference(i); | |||||
| if (newCount == 0) | |||||
| if (trc.threadID == threadId) | |||||
| { | |||||
| if (--(trc.count) == 0) | |||||
| { | { | ||||
| readerThreads.removeRange (i, 2); | |||||
| readerThreads.remove (i); | |||||
| waitEvent.signal(); | waitEvent.signal(); | ||||
| } | } | ||||
| else | |||||
| { | |||||
| readerThreads.set (i + 1, (Thread::ThreadID) newCount); | |||||
| } | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -112,8 +103,8 @@ void ReadWriteLock::enterWrite() const noexcept | |||||
| { | { | ||||
| if (readerThreads.size() + numWriters == 0 | if (readerThreads.size() + numWriters == 0 | ||||
| || threadId == writerThreadId | || threadId == writerThreadId | ||||
| || (readerThreads.size() == 2 | |||||
| && readerThreads.getUnchecked(0) == threadId)) | |||||
| || (readerThreads.size() == 1 | |||||
| && readerThreads.getReference(0).threadID == threadId)) | |||||
| { | { | ||||
| writerThreadId = threadId; | writerThreadId = threadId; | ||||
| ++numWriters; | ++numWriters; | ||||
| @@ -135,8 +126,8 @@ bool ReadWriteLock::tryEnterWrite() const noexcept | |||||
| if (readerThreads.size() + numWriters == 0 | if (readerThreads.size() + numWriters == 0 | ||||
| || threadId == writerThreadId | || threadId == writerThreadId | ||||
| || (readerThreads.size() == 2 | |||||
| && readerThreads.getUnchecked(0) == threadId)) | |||||
| || (readerThreads.size() == 1 | |||||
| && readerThreads.getReference(0).threadID == threadId)) | |||||
| { | { | ||||
| writerThreadId = threadId; | writerThreadId = threadId; | ||||
| ++numWriters; | ++numWriters; | ||||
| @@ -129,7 +129,14 @@ private: | |||||
| WaitableEvent waitEvent; | WaitableEvent waitEvent; | ||||
| mutable int numWaitingWriters, numWriters; | mutable int numWaitingWriters, numWriters; | ||||
| mutable Thread::ThreadID writerThreadId; | mutable Thread::ThreadID writerThreadId; | ||||
| mutable Array <Thread::ThreadID> readerThreads; | |||||
| struct ThreadRecursionCount | |||||
| { | |||||
| Thread::ThreadID threadID; | |||||
| int count; | |||||
| }; | |||||
| mutable Array <ThreadRecursionCount> readerThreads; | |||||
| JUCE_DECLARE_NON_COPYABLE (ReadWriteLock); | JUCE_DECLARE_NON_COPYABLE (ReadWriteLock); | ||||
| }; | }; | ||||