upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)

This commit is contained in:
Alex Birch
2019-06-22 20:41:38 +01:00
parent d22c2cd4fa
commit 9ee566b251
1140 changed files with 67534 additions and 105952 deletions

View File

@ -30,8 +30,8 @@ AbstractFifo::AbstractFifo (int capacity) noexcept : bufferSize (capacity)
AbstractFifo::~AbstractFifo() {}
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
int AbstractFifo::getNumReady() const noexcept
{
@ -54,7 +54,8 @@ void AbstractFifo::setTotalSize (int newSize) noexcept
}
//==============================================================================
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1,
int& startIndex2, int& blockSize2) const noexcept
{
auto vs = validStart.get();
auto ve = validEnd.get();
@ -91,7 +92,8 @@ void AbstractFifo::finishedWrite (int numWritten) noexcept
validEnd = newEnd;
}
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1,
int& startIndex2, int& blockSize2) const noexcept
{
auto vs = validStart.get();
auto ve = validEnd.get();
@ -129,13 +131,6 @@ void AbstractFifo::finishedRead (int numRead) noexcept
}
//==============================================================================
template <AbstractFifo::ReadOrWrite mode>
AbstractFifo::ScopedReadWrite<mode>::ScopedReadWrite (AbstractFifo& f, int num) noexcept
: fifo (&f)
{
prepare (*fifo, num);
}
template <AbstractFifo::ReadOrWrite mode>
AbstractFifo::ScopedReadWrite<mode>::ScopedReadWrite (ScopedReadWrite&& other) noexcept
: startIndex1 (other.startIndex1),
@ -154,13 +149,6 @@ AbstractFifo::ScopedReadWrite<mode>::operator= (ScopedReadWrite&& other) noexcep
return *this;
}
template <AbstractFifo::ReadOrWrite mode>
AbstractFifo::ScopedReadWrite<mode>::~ScopedReadWrite() noexcept
{
if (fifo != nullptr)
finish (*fifo, blockSize1 + blockSize2);
}
template <AbstractFifo::ReadOrWrite mode>
void AbstractFifo::ScopedReadWrite<mode>::swap (ScopedReadWrite& other) noexcept
{
@ -171,33 +159,13 @@ void AbstractFifo::ScopedReadWrite<mode>::swap (ScopedReadWrite& other) noexcept
std::swap (other.blockSize2, blockSize2);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::prepare (AbstractFifo& f, int num) noexcept
{
f.prepareToRead (num, startIndex1, blockSize1, startIndex2, blockSize2);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::prepare (AbstractFifo& f, int num) noexcept
{
f.prepareToWrite (num, startIndex1, blockSize1, startIndex2, blockSize2);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::finish (AbstractFifo& f, int num) noexcept
{
f.finishedRead (num);
}
template<>
void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::finish (AbstractFifo& f, int num) noexcept
{
f.finishedWrite (num);
}
template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>;
template class AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>;
AbstractFifo::ScopedRead AbstractFifo::read (int numToRead) noexcept { return { *this, numToRead }; }
AbstractFifo::ScopedWrite AbstractFifo::write (int numToWrite) noexcept { return { *this, numToWrite }; }
//==============================================================================
#if JUCE_UNIT_TESTS

View File

@ -38,13 +38,8 @@ namespace juce
e.g.
@code
class MyFifo
struct MyFifo
{
public:
MyFifo() : abstractFifo (1024)
{
}
void addToFifo (const int* someData, int numItems)
{
int start1, size1, start2, size2;
@ -73,9 +68,8 @@ namespace juce
abstractFifo.finishedRead (size1 + size2);
}
private:
AbstractFifo abstractFifo;
int myBuffer [1024];
AbstractFifo abstractFifo { 1024 };
int myBuffer[1024];
};
@endcode
@ -225,7 +219,10 @@ public:
This object will hold a pointer back to the fifo, so make sure that
the fifo outlives this object.
*/
ScopedReadWrite (AbstractFifo&, int num) noexcept;
ScopedReadWrite (AbstractFifo& f, int num) noexcept : fifo (&f)
{
prepare (*fifo, num);
}
ScopedReadWrite (const ScopedReadWrite&) = delete;
ScopedReadWrite (ScopedReadWrite&&) noexcept;
@ -236,7 +233,11 @@ public:
/** Calls finishedRead or finishedWrite if this is a non-null scoped
reader/writer.
*/
~ScopedReadWrite() noexcept;
~ScopedReadWrite() noexcept
{
if (fifo != nullptr)
finish (*fifo, blockSize1 + blockSize2);
}
/** Calls the passed function with each index that was deemed valid
for the current read/write operation.
@ -281,7 +282,7 @@ public:
} // readHandle goes out of scope here, finishing the read operation
@endcode
*/
ScopedRead read (int numToRead) noexcept { return { *this, numToRead }; }
ScopedRead read (int numToRead) noexcept;
/** Replaces prepareToWrite/finishedWrite with a single function.
This function returns an object which contains the start indices and
@ -303,7 +304,7 @@ public:
} // writeHandle goes out of scope here, finishing the write operation
@endcode
*/
ScopedWrite write (int numToWrite) noexcept { return { *this, numToWrite }; }
ScopedWrite write (int numToWrite) noexcept;
private:
//==============================================================================
@ -313,4 +314,29 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
};
template<>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::finish (AbstractFifo& f, int num) noexcept
{
f.finishedRead (num);
}
template<>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::finish (AbstractFifo& f, int num) noexcept
{
f.finishedWrite (num);
}
template<>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::read>::prepare (AbstractFifo& f, int num) noexcept
{
f.prepareToRead (num, startIndex1, blockSize1, startIndex2, blockSize2);
}
template<>
inline void AbstractFifo::ScopedReadWrite<AbstractFifo::ReadOrWrite::write>::prepare (AbstractFifo& f, int num) noexcept
{
f.prepareToWrite (num, startIndex1, blockSize1, startIndex2, blockSize2);
}
} // namespace juce

View File

@ -60,51 +60,40 @@ private:
public:
//==============================================================================
/** Creates an empty array. */
Array() noexcept
{
}
Array() = default;
/** Creates a copy of another array.
@param other the array to copy
*/
Array (const Array<ElementType, TypeOfCriticalSectionToUse>& other)
Array (const Array& other)
{
const ScopedLockType lock (other.getLock());
numUsed = other.numUsed;
data.setAllocatedSize (other.numUsed);
for (int i = 0; i < numUsed; ++i)
new (data.elements + i) ElementType (other.data.elements[i]);
values.addArray (other.values.begin(), other.values.size());
}
Array (Array<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
: data (static_cast<ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&&> (other.data)),
numUsed (other.numUsed)
Array (Array&& other) noexcept
: values (std::move (other.values))
{
other.numUsed = 0;
}
/** Initalises from a null-terminated raw array of values.
@param values the array to copy from
@param data the data to copy from
*/
template <typename TypeToCreateFrom>
explicit Array (const TypeToCreateFrom* values)
explicit Array (const TypeToCreateFrom* data)
{
while (*values != TypeToCreateFrom())
add (*values++);
add (*data++);
}
/** Initalises from a raw array of values.
@param values the array to copy from
@param data the data to copy from
@param numValues the number of values in the array
*/
template <typename TypeToCreateFrom>
Array (const TypeToCreateFrom* values, int numValues) : numUsed (numValues)
Array (const TypeToCreateFrom* data, int numValues)
{
data.setAllocatedSize (numValues);
for (int i = 0; i < numValues; ++i)
new (data.elements + i) ElementType (values[i]);
values.addArray (data, numValues);
}
/** Initalises an Array of size 1 containing a single element. */
@ -116,23 +105,21 @@ public:
/** Initalises an Array of size 1 containing a single element. */
Array (ElementType&& singleElementToAdd)
{
add (static_cast<ElementType&&> (singleElementToAdd));
add (std::move (singleElementToAdd));
}
/** Initalises an Array from a list of items. */
template <typename... OtherElements>
Array (const ElementType& firstNewElement, OtherElements... otherElements)
{
data.setAllocatedSize (1 + (int) sizeof... (otherElements));
addAssumingCapacityIsReady (firstNewElement, otherElements...);
values.add (firstNewElement, otherElements...);
}
/** Initalises an Array from a list of items. */
template <typename... OtherElements>
Array (ElementType&& firstNewElement, OtherElements... otherElements)
{
data.setAllocatedSize (1 + (int) sizeof... (otherElements));
addAssumingCapacityIsReady (static_cast<ElementType&&> (firstNewElement), otherElements...);
values.add (std::move (firstNewElement), otherElements...);
}
template <typename TypeToCreateFrom>
@ -142,10 +129,7 @@ public:
}
/** Destructor. */
~Array()
{
deleteAllElements();
}
~Array() = default;
/** Copies another array.
@param other the array to copy
@ -164,10 +148,7 @@ public:
Array& operator= (Array&& other) noexcept
{
const ScopedLockType lock (getLock());
deleteAllElements();
data = static_cast<ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&&> (other.data);
numUsed = other.numUsed;
other.numUsed = 0;
values = std::move (other.values);
return *this;
}
@ -182,15 +163,7 @@ public:
{
const ScopedLockType lock (getLock());
const typename OtherArrayType::ScopedLockType lock2 (other.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 values == other;
}
/** Compares this array to another one.
@ -215,9 +188,8 @@ public:
void clear()
{
const ScopedLockType lock (getLock());
deleteAllElements();
data.setAllocatedSize (0);
numUsed = 0;
clearQuick();
values.setAllocatedSize (0);
}
/** Removes all elements from the array without freeing the array's allocated storage.
@ -226,8 +198,7 @@ public:
void clearQuick()
{
const ScopedLockType lock (getLock());
deleteAllElements();
numUsed = 0;
values.clear();
}
/** Fills the Array with the provided value. */
@ -243,13 +214,14 @@ public:
/** Returns the current number of elements in the array. */
inline int size() const noexcept
{
return numUsed;
const ScopedLockType lock (getLock());
return values.size();
}
/** Returns true if the array is empty, false otherwise. */
inline bool isEmpty() const noexcept
{
return numUsed == 0;
return size() == 0;
}
/** Returns one of the elements in the array.
@ -262,17 +234,10 @@ public:
@param index the index of the element being requested (0 is the first element in the array)
@see getUnchecked, getFirst, getLast
*/
ElementType operator[] (const int index) const
ElementType operator[] (int index) const
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (index, numUsed))
{
jassert (data.elements != nullptr);
return data.elements[index];
}
return ElementType();
return values.getValueWithDefault (index);
}
/** Returns one of the elements in the array, without checking the index passed in.
@ -284,11 +249,10 @@ public:
@param index the index of the element being requested (0 is the first element in the array)
@see operator[], getFirst, getLast
*/
inline ElementType getUnchecked (const int index) const
inline ElementType getUnchecked (int index) const
{
const ScopedLockType lock (getLock());
jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
return data.elements[index];
return values[index];
}
/** Returns a direct reference to one of the elements in the array, without checking the index passed in.
@ -300,44 +264,29 @@ public:
@param index the index of the element being requested (0 is the first element in the array)
@see operator[], getFirst, getLast
*/
inline ElementType& getReference (const int index) const noexcept
inline ElementType& getReference (int index) const noexcept
{
const ScopedLockType lock (getLock());
jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
return data.elements[index];
return values[index];
}
/** Returns the first element in the array, or a default value if the array is empty.
@see operator[], getUnchecked, getLast
*/
inline ElementType getFirst() const
inline ElementType getFirst() const noexcept
{
const ScopedLockType lock (getLock());
if (numUsed > 0)
{
jassert (data.elements != nullptr);
return data.elements[0];
}
return ElementType();
return values.getFirst();
}
/** Returns the last element in the array, or a default value if the array is empty.
@see operator[], getUnchecked, getFirst
*/
inline ElementType getLast() const
inline ElementType getLast() const noexcept
{
const ScopedLockType lock (getLock());
if (numUsed > 0)
{
jassert (data.elements != nullptr);
return data.elements[numUsed - 1];
}
return ElementType();
return values.getLast();
}
/** Returns a pointer to the actual array data.
@ -346,7 +295,7 @@ public:
*/
inline ElementType* getRawDataPointer() noexcept
{
return data.elements;
return values.begin();
}
//==============================================================================
@ -355,7 +304,7 @@ public:
*/
inline ElementType* begin() const noexcept
{
return data.elements;
return values.begin();
}
/** Returns a pointer to the element which follows the last element in the array.
@ -363,12 +312,15 @@ public:
*/
inline ElementType* end() const noexcept
{
#if JUCE_DEBUG
if (data.elements == nullptr || numUsed <= 0) // (to keep static analysers happy)
return data.elements;
#endif
return values.end();
}
return data.elements + numUsed;
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ElementType* data() const noexcept
{
return begin();
}
//==============================================================================
@ -383,12 +335,12 @@ public:
int indexOf (ParameterType elementToLookFor) const
{
const ScopedLockType lock (getLock());
auto e = data.elements.get();
auto endPtr = e + numUsed;
auto e = values.begin();
auto endPtr = values.end();
for (; e != endPtr; ++e)
if (elementToLookFor == *e)
return static_cast<int> (e - data.elements.get());
return static_cast<int> (e - values.begin());
return -1;
}
@ -401,8 +353,8 @@ public:
bool contains (ParameterType elementToLookFor) const
{
const ScopedLockType lock (getLock());
auto e = data.elements.get();
auto endPtr = e + numUsed;
auto e = values.begin();
auto endPtr = values.end();
for (; e != endPtr; ++e)
if (elementToLookFor == *e)
@ -419,8 +371,7 @@ public:
void add (const ElementType& newElement)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
new (data.elements + numUsed++) ElementType (newElement);
values.add (newElement);
}
/** Appends a new element at the end of the array.
@ -430,8 +381,7 @@ public:
void add (ElementType&& newElement)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
new (data.elements + numUsed++) ElementType (static_cast<ElementType&&> (newElement));
values.add (std::move (newElement));
}
/** Appends multiple new elements at the end of the array. */
@ -439,8 +389,7 @@ public:
void add (const ElementType& firstNewElement, OtherElements... otherElements)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
addAssumingCapacityIsReady (firstNewElement, otherElements...);
values.add (firstNewElement, otherElements...);
}
/** Appends multiple new elements at the end of the array. */
@ -448,8 +397,7 @@ public:
void add (ElementType&& firstNewElement, OtherElements... otherElements)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
addAssumingCapacityIsReady (static_cast<ElementType&&> (firstNewElement), otherElements...);
values.add (std::move (firstNewElement), otherElements...);
}
/** Inserts a new element into the array at a given position.
@ -467,24 +415,7 @@ public:
void insert (int indexToInsertAt, ParameterType newElement)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
if (isPositiveAndBelow (indexToInsertAt, numUsed))
{
auto* insertPos = data.elements + indexToInsertAt;
auto numberToMove = numUsed - indexToInsertAt;
if (numberToMove > 0)
memmove (insertPos + 1, insertPos, ((size_t) numberToMove) * sizeof (ElementType));
new (insertPos) ElementType (newElement);
++numUsed;
}
else
{
new (data.elements + numUsed++) ElementType (newElement);
}
values.insert (indexToInsertAt, newElement, 1);
}
/** Inserts multiple copies of an element into the array at a given position.
@ -505,28 +436,7 @@ public:
if (numberOfTimesToInsertIt > 0)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt);
ElementType* insertPos;
if (isPositiveAndBelow (indexToInsertAt, numUsed))
{
insertPos = data.elements + indexToInsertAt;
auto numberToMove = numUsed - indexToInsertAt;
memmove (insertPos + numberOfTimesToInsertIt, insertPos, ((size_t) numberToMove) * sizeof (ElementType));
}
else
{
insertPos = data.elements + numUsed;
}
numUsed += numberOfTimesToInsertIt;
while (--numberOfTimesToInsertIt >= 0)
{
new (insertPos) ElementType (newElement);
++insertPos; // NB: this increment is done separately from the
// new statement to avoid a compiler bug in VS2014
}
values.insert (indexToInsertAt, newElement, numberOfTimesToInsertIt);
}
}
@ -549,24 +459,7 @@ public:
if (numberOfElements > 0)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + numberOfElements);
ElementType* insertPos = data.elements;
if (isPositiveAndBelow (indexToInsertAt, numUsed))
{
insertPos += indexToInsertAt;
auto numberToMove = numUsed - indexToInsertAt;
memmove (insertPos + numberOfElements, insertPos, (size_t) numberToMove * sizeof (ElementType));
}
else
{
insertPos += numUsed;
}
numUsed += numberOfElements;
while (--numberOfElements >= 0)
new (insertPos++) ElementType (*newElements++);
values.insertArray (indexToInsertAt, newElements, numberOfElements);
}
}
@ -599,20 +492,20 @@ public:
@param newValue the new value to set for this index.
@see add, insert
*/
void set (const int indexToChange, ParameterType newValue)
void set (int indexToChange, ParameterType newValue)
{
jassert (indexToChange >= 0);
const ScopedLockType lock (getLock());
if (indexToChange >= 0)
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToChange, numUsed))
{
jassert (data.elements != nullptr);
data.elements[indexToChange] = newValue;
if (indexToChange < values.size())
values[indexToChange] = newValue;
else
values.add (newValue);
}
else if (indexToChange >= 0)
else
{
data.ensureAllocatedSize (numUsed + 1);
new (data.elements + numUsed++) ElementType (newValue);
jassertfalse;
}
}
@ -625,11 +518,11 @@ public:
@param newValue the new value to set for this index.
@see set, getUnchecked
*/
void setUnchecked (const int indexToChange, ParameterType newValue)
void setUnchecked (int indexToChange, ParameterType newValue)
{
const ScopedLockType lock (getLock());
jassert (isPositiveAndBelow (indexToChange, numUsed));
data.elements[indexToChange] = newValue;
jassert (isPositiveAndBelow (indexToChange, values.size()));
values[indexToChange] = newValue;
}
/** Adds elements from an array to the end of this array.
@ -645,28 +538,14 @@ public:
const ScopedLockType lock (getLock());
if (numElementsToAdd > 0)
{
data.ensureAllocatedSize (numUsed + numElementsToAdd);
while (--numElementsToAdd >= 0)
{
new (data.elements + numUsed) ElementType (*elementsToAdd++);
++numUsed;
}
}
values.addArray (elementsToAdd, numElementsToAdd);
}
template <typename TypeToCreateFrom>
void addArray (const std::initializer_list<TypeToCreateFrom>& items)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + (int) items.size());
for (auto& item : items)
{
new (data.elements + numUsed) ElementType (item);
++numUsed;
}
values.addArray (items);
}
/** Adds elements from a null-terminated array of pointers to the end of this array.
@ -696,8 +575,21 @@ public:
{
const ScopedLockType lock1 (getLock());
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
data.swapWith (otherArray.data);
std::swap (numUsed, otherArray.numUsed);
values.swapWith (otherArray.values);
}
/** Adds elements from another array to the end of this array.
@param arrayToAddFrom the array from which to copy the elements
@see add
*/
template <class OtherArrayType>
void addArray (const OtherArrayType& arrayToAddFrom)
{
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
const ScopedLockType lock2 (getLock());
values.addArray (arrayToAddFrom);
}
/** Adds elements from another array to the end of this array.
@ -710,29 +602,15 @@ public:
@see add
*/
template <class OtherArrayType>
void addArray (const OtherArrayType& arrayToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1)
typename std::enable_if<! std::is_pointer<OtherArrayType>::value, void>::type
addArray (const OtherArrayType& arrayToAddFrom,
int startIndex,
int numElementsToAdd = -1)
{
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
const ScopedLockType lock2 (getLock());
{
const ScopedLockType lock2 (getLock());
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
numElementsToAdd = arrayToAddFrom.size() - startIndex;
data.ensureAllocatedSize (numUsed + numElementsToAdd);
while (--numElementsToAdd >= 0)
addAssumingCapacityIsReady (arrayToAddFrom.getUnchecked (startIndex++));
}
values.addArray (arrayToAddFrom, startIndex, numElementsToAdd);
}
/** This will enlarge or shrink the array to the given number of elements, by adding
@ -742,13 +620,13 @@ public:
until its size is as specified. If its size is larger than the target, items will be
removed from its end to shorten it.
*/
void resize (const int targetNumItems)
void resize (int targetNumItems)
{
jassert (targetNumItems >= 0);
auto numToAdd = targetNumItems - numUsed;
auto numToAdd = targetNumItems - values.size();
if (numToAdd > 0)
insertMultiple (numUsed, ElementType(), numToAdd);
insertMultiple (values.size(), ElementType(), numToAdd);
else if (numToAdd < 0)
removeRange (targetNumItems, -numToAdd);
}
@ -769,7 +647,7 @@ public:
int addSorted (ElementComparator& comparator, ParameterType newElement)
{
const ScopedLockType lock (getLock());
auto index = findInsertIndexInSortedArray (comparator, data.elements.get(), newElement, 0, numUsed);
auto index = findInsertIndexInSortedArray (comparator, values.begin(), newElement, 0, values.size());
insert (index, newElement);
return index;
}
@ -809,12 +687,12 @@ public:
const ScopedLockType lock (getLock());
for (int s = 0, e = numUsed;;)
for (int s = 0, e = values.size();;)
{
if (s >= e)
return -1;
if (comparator.compareElements (elementToLookFor, data.elements[s]) == 0)
if (comparator.compareElements (elementToLookFor, values[s]) == 0)
return s;
auto halfway = (s + e) / 2;
@ -822,7 +700,7 @@ public:
if (halfway == s)
return -1;
if (comparator.compareElements (elementToLookFor, data.elements[halfway]) >= 0)
if (comparator.compareElements (elementToLookFor, values[halfway]) >= 0)
s = halfway;
else
e = halfway;
@ -843,11 +721,8 @@ public:
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
{
jassert (data.elements != nullptr);
if (isPositiveAndBelow (indexToRemove, values.size()))
removeInternal (indexToRemove);
}
}
/** Removes an element from the array.
@ -864,15 +739,14 @@ public:
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
if (isPositiveAndBelow (indexToRemove, values.size()))
{
jassert (data.elements != nullptr);
ElementType removed (data.elements[indexToRemove]);
ElementType removed (values[indexToRemove]);
removeInternal (indexToRemove);
return removed;
}
return {};
return ElementType();
}
/** Removes an element from the array.
@ -890,10 +764,10 @@ public:
jassert (elementToRemove != nullptr);
const ScopedLockType lock (getLock());
jassert (data.elements != nullptr);
auto indexToRemove = (int) (elementToRemove - data.elements);
jassert (values.begin() != nullptr);
auto indexToRemove = (int) (elementToRemove - values.begin());
if (! isPositiveAndBelow (indexToRemove, numUsed))
if (! isPositiveAndBelow (indexToRemove, values.size()))
{
jassertfalse;
return;
@ -913,9 +787,9 @@ public:
void removeFirstMatchingValue (ParameterType valueToRemove)
{
const ScopedLockType lock (getLock());
auto* e = data.elements.get();
auto* e = values.begin();
for (int i = 0; i < numUsed; ++i)
for (int i = 0; i < values.size(); ++i)
{
if (valueToRemove == e[i])
{
@ -939,9 +813,9 @@ public:
int numRemoved = 0;
const ScopedLockType lock (getLock());
for (int i = numUsed; --i >= 0;)
for (int i = values.size(); --i >= 0;)
{
if (valueToRemove == data.elements[i])
if (valueToRemove == values[i])
{
removeInternal (i);
++numRemoved;
@ -963,14 +837,14 @@ public:
@see remove, removeRange, removeAllInstancesOf
*/
template <typename PredicateType>
int removeIf (PredicateType predicate)
int removeIf (PredicateType&& predicate)
{
int numRemoved = 0;
const ScopedLockType lock (getLock());
for (int i = numUsed; --i >= 0;)
for (int i = values.size(); --i >= 0;)
{
if (predicate (data.elements[i]))
if (predicate (values[i]))
{
removeInternal (i);
++numRemoved;
@ -995,23 +869,14 @@ public:
void removeRange (int startIndex, int numberToRemove)
{
const ScopedLockType lock (getLock());
auto endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
startIndex = jlimit (0, numUsed, startIndex);
if (endIndex > startIndex)
auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
startIndex = jlimit (0, values.size(), startIndex);
numberToRemove = endIndex - startIndex;
if (numberToRemove > 0)
{
auto* e = data.elements + startIndex;
numberToRemove = endIndex - startIndex;
for (int i = 0; i < numberToRemove; ++i)
e[i].~ElementType();
auto numToShift = numUsed - endIndex;
if (numToShift > 0)
memmove (e, e + numberToRemove, ((size_t) numToShift) * sizeof (ElementType));
numUsed -= numberToRemove;
values.removeElements (startIndex, numberToRemove);
minimiseStorageAfterRemoval();
}
}
@ -1023,16 +888,18 @@ public:
*/
void removeLast (int howManyToRemove = 1)
{
const ScopedLockType lock (getLock());
jassert (howManyToRemove >= 0);
if (howManyToRemove > numUsed)
howManyToRemove = numUsed;
if (howManyToRemove > 0)
{
const ScopedLockType lock (getLock());
for (int i = 1; i <= howManyToRemove; ++i)
data.elements[numUsed - i].~ElementType();
if (howManyToRemove > values.size())
howManyToRemove = values.size();
numUsed -= howManyToRemove;
minimiseStorageAfterRemoval();
values.removeElements (values.size() - howManyToRemove, howManyToRemove);
minimiseStorageAfterRemoval();
}
}
/** Removes any elements which are also in another array.
@ -1054,8 +921,8 @@ public:
{
if (otherArray.size() > 0)
{
for (int i = numUsed; --i >= 0;)
if (otherArray.contains (data.elements[i]))
for (int i = values.size(); --i >= 0;)
if (otherArray.contains (values[i]))
removeInternal (i);
}
}
@ -1082,8 +949,8 @@ public:
}
else
{
for (int i = numUsed; --i >= 0;)
if (! otherArray.contains (data.elements[i]))
for (int i = values.size(); --i >= 0;)
if (! otherArray.contains (values[i]))
removeInternal (i);
}
}
@ -1100,13 +967,7 @@ public:
void swap (int index1, int index2)
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (index1, numUsed)
&& isPositiveAndBelow (index2, numUsed))
{
std::swap (data.elements[index1],
data.elements[index2]);
}
values.swap (index1, index2);
}
/** Moves one of the values to a different position.
@ -1128,30 +989,7 @@ public:
if (currentIndex != newIndex)
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (currentIndex, numUsed))
{
if (! isPositiveAndBelow (newIndex, numUsed))
newIndex = numUsed - 1;
char tempCopy[sizeof (ElementType)];
memcpy (tempCopy, data.elements + currentIndex, sizeof (ElementType));
if (newIndex > currentIndex)
{
memmove (data.elements + currentIndex,
data.elements + currentIndex + 1,
sizeof (ElementType) * (size_t) (newIndex - currentIndex));
}
else
{
memmove (data.elements + newIndex + 1,
data.elements + newIndex,
sizeof (ElementType) * (size_t) (currentIndex - newIndex));
}
memcpy (data.elements + newIndex, tempCopy, sizeof (ElementType));
}
values.move (currentIndex, newIndex);
}
}
@ -1165,7 +1003,7 @@ public:
void minimiseStorageOverheads()
{
const ScopedLockType lock (getLock());
data.shrinkToNoMoreThan (numUsed);
values.shrinkToNoMoreThan (values.size());
}
/** Increases the array's internal storage to hold a minimum number of elements.
@ -1174,10 +1012,10 @@ public:
the array won't have to keep dynamically resizing itself as the elements
are added, and it'll therefore be more efficient.
*/
void ensureStorageAllocated (const int minNumElements)
void ensureStorageAllocated (int minNumElements)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (minNumElements);
values.ensureAllocatedSize (minNumElements);
}
//==============================================================================
@ -1219,12 +1057,12 @@ public:
*/
template <class ElementComparator>
void sort (ElementComparator& comparator,
const bool retainOrderOfEquivalentItems = false)
bool retainOrderOfEquivalentItems = false)
{
const ScopedLockType lock (getLock());
ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
sortArray (comparator, data.elements.get(), 0, size() - 1, retainOrderOfEquivalentItems);
sortArray (comparator, values.begin(), 0, size() - 1, retainOrderOfEquivalentItems);
}
//==============================================================================
@ -1232,7 +1070,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 values; }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
@ -1247,49 +1085,18 @@ public:
private:
//==============================================================================
ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse> data;
int numUsed = 0;
ArrayBase<ElementType, TypeOfCriticalSectionToUse> values;
void removeInternal (const int indexToRemove)
void removeInternal (int indexToRemove)
{
--numUsed;
auto* e = data.elements + indexToRemove;
e->~ElementType();
auto numberToShift = numUsed - indexToRemove;
if (numberToShift > 0)
memmove (e, e + 1, ((size_t) numberToShift) * sizeof (ElementType));
values.removeElements (indexToRemove, 1);
minimiseStorageAfterRemoval();
}
inline void deleteAllElements() noexcept
{
for (int i = 0; i < numUsed; ++i)
data.elements[i].~ElementType();
}
void minimiseStorageAfterRemoval()
{
if (data.numAllocated > jmax (minimumAllocatedSize, numUsed * 2))
data.shrinkToNoMoreThan (jmax (numUsed, jmax (minimumAllocatedSize, 64 / (int) sizeof (ElementType))));
}
void addAssumingCapacityIsReady (const ElementType& e) { new (data.elements + numUsed++) ElementType (e); }
void addAssumingCapacityIsReady (ElementType&& e) { new (data.elements + numUsed++) ElementType (static_cast<ElementType&&> (e)); }
template <typename... OtherElements>
void addAssumingCapacityIsReady (const ElementType& firstNewElement, OtherElements... otherElements)
{
addAssumingCapacityIsReady (firstNewElement);
addAssumingCapacityIsReady (otherElements...);
}
template <typename... OtherElements>
void addAssumingCapacityIsReady (ElementType&& firstNewElement, OtherElements... otherElements)
{
addAssumingCapacityIsReady (static_cast<ElementType&&> (firstNewElement));
addAssumingCapacityIsReady (otherElements...);
if (values.capacity() > jmax (minimumAllocatedSize, values.size() * 2))
values.shrinkToNoMoreThan (jmax (values.size(), jmax (minimumAllocatedSize, 64 / (int) sizeof (ElementType))));
}
};

View File

@ -27,13 +27,9 @@ namespace juce
/**
Implements some basic array storage allocation functions.
This class isn't really for public use - it's used by the other
array classes, but might come in handy for some purposes.
It inherits from a critical section class to allow the arrays to use
the "empty base class optimisation" pattern to reduce their footprint.
@see Array, OwnedArray, ReferenceCountedArray
This class isn't really for public use - it used to be part of the
container classes but has since been superseded by ArrayBase. Eventually
it will be removed from the API.
@tags{Core}
*/
@ -43,24 +39,20 @@ class ArrayAllocationBase : public TypeOfCriticalSectionToUse
public:
//==============================================================================
/** Creates an empty array. */
ArrayAllocationBase() noexcept
{
}
ArrayAllocationBase() = default;
/** Destructor. */
~ArrayAllocationBase() noexcept
{
}
~ArrayAllocationBase() = default;
ArrayAllocationBase (ArrayAllocationBase&& other) noexcept
: elements (static_cast<HeapBlock<ElementType>&&> (other.elements)),
: elements (std::move (other.elements)),
numAllocated (other.numAllocated)
{
}
ArrayAllocationBase& operator= (ArrayAllocationBase&& other) noexcept
{
elements = static_cast<HeapBlock<ElementType>&&> (other.elements);
elements = std::move (other.elements);
numAllocated = other.numAllocated;
return *this;
}

View File

@ -0,0 +1,600 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2018 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#if JUCE_UNIT_TESTS
namespace ArrayBaseTestsHelpers
{
class TriviallyCopyableType
{
public:
TriviallyCopyableType() = default;
TriviallyCopyableType (int v)
: value (v)
{}
TriviallyCopyableType (float v)
: value ((int) v)
{}
bool operator== (const TriviallyCopyableType& other) const
{
return getValue() == other.getValue();
}
int getValue() const { return value; }
private:
int value { -1111 };
};
class NonTriviallyCopyableType
{
public:
NonTriviallyCopyableType() = default;
NonTriviallyCopyableType (int v)
: value (v)
{}
NonTriviallyCopyableType (float v)
: value ((int) v)
{}
NonTriviallyCopyableType (const NonTriviallyCopyableType& other)
: value (other.value)
{}
NonTriviallyCopyableType& operator= (const NonTriviallyCopyableType& other)
{
value = other.value;
return *this;
}
bool operator== (const NonTriviallyCopyableType& other) const
{
return getValue() == other.getValue();
}
int getValue() const { return *ptr; }
private:
int value { -1111 };
int* ptr = &value;
};
}
bool operator== (const ArrayBaseTestsHelpers::TriviallyCopyableType& tct,
const ArrayBaseTestsHelpers::NonTriviallyCopyableType& ntct)
{
return tct.getValue() == ntct.getValue();
}
bool operator== (const ArrayBaseTestsHelpers::NonTriviallyCopyableType& ntct,
const ArrayBaseTestsHelpers::TriviallyCopyableType& tct)
{
return tct == ntct;
}
class ArrayBaseTests : public UnitTest
{
using CopyableType = ArrayBaseTestsHelpers::TriviallyCopyableType;
using NoncopyableType = ArrayBaseTestsHelpers::NonTriviallyCopyableType;
#if ! (defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__))
static_assert (std::is_trivially_copyable<CopyableType>::value,
"Test TriviallyCopyableType is not trivially copyable");
static_assert (! std::is_trivially_copyable<NoncopyableType>::value,
"Test NonTriviallyCopyableType is trivially copyable");
#endif
public:
ArrayBaseTests()
: UnitTest ("ArrayBase", "Containers")
{}
void runTest() override
{
beginTest ("grow capacity");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
int originalCapacity = 4;
referenceContainer.reserve ((size_t) originalCapacity);
expectEquals ((int) referenceContainer.capacity(), originalCapacity);
copyableContainer.setAllocatedSize (originalCapacity);
expectEquals (copyableContainer.capacity(), originalCapacity);
noncopyableContainer.setAllocatedSize (originalCapacity);
expectEquals (noncopyableContainer.capacity(), originalCapacity);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
addData (referenceContainer, copyableContainer, noncopyableContainer, 33);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
expect ((int) referenceContainer.capacity() != originalCapacity);
expect (copyableContainer.capacity() != originalCapacity);
expect (noncopyableContainer.capacity() != originalCapacity);
}
beginTest ("shrink capacity");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
int numElements = 45;
addData (referenceContainer, copyableContainer, noncopyableContainer, numElements);
copyableContainer.shrinkToNoMoreThan (numElements);
noncopyableContainer.setAllocatedSize (numElements + 1);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
referenceContainer.clear();
copyableContainer.removeElements (0, numElements);
noncopyableContainer.removeElements (0, numElements);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
copyableContainer.setAllocatedSize (0);
noncopyableContainer.setAllocatedSize (0);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
addData (referenceContainer, copyableContainer, noncopyableContainer, numElements);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("equality");
{
std::vector<int> referenceContainer = { 1, 2, 3 };
ArrayBase<int, DummyCriticalSection> testContainer1, testContainer2;
for (auto i : referenceContainer)
{
testContainer1.add (i);
testContainer2.add (i);
}
expect (testContainer1 == referenceContainer);
expect (testContainer2 == testContainer1);
testContainer1.ensureAllocatedSize (257);
referenceContainer.shrink_to_fit();
expect (testContainer1 == referenceContainer);
expect (testContainer2 == testContainer1);
testContainer1.removeElements (0, 1);
expect (testContainer1 != referenceContainer);
expect (testContainer2 != testContainer1);
}
beginTest ("accessors");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
addData (referenceContainer, copyableContainer, noncopyableContainer, 3);
int testValue = -123;
referenceContainer[0] = testValue;
copyableContainer[0] = testValue;
noncopyableContainer[0] = testValue;
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
expect (copyableContainer .getFirst().getValue() == testValue);
expect (noncopyableContainer.getFirst().getValue() == testValue);
auto last = referenceContainer.back().getValue();
expectEquals (copyableContainer .getLast().getValue(), last);
expectEquals (noncopyableContainer.getLast().getValue(), last);
ArrayBase<CopyableType, DummyCriticalSection> copyableEmpty;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableEmpty;
auto defualtValue = CopyableType().getValue();
expectEquals (defualtValue, NoncopyableType().getValue());
expectEquals (copyableEmpty .getFirst().getValue(), defualtValue);
expectEquals (noncopyableEmpty.getFirst().getValue(), defualtValue);
expectEquals (copyableEmpty .getLast() .getValue(), defualtValue);
expectEquals (noncopyableEmpty.getLast() .getValue(), defualtValue);
ArrayBase<float*, DummyCriticalSection> floatPointers;
expect (floatPointers.getValueWithDefault (-3) == nullptr);
}
beginTest ("add moved");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
for (int i = 0; i < 5; ++i)
{
CopyableType ref (-i);
CopyableType ct (-i);
NoncopyableType nct (-i);
referenceContainer.push_back (std::move (ref));
copyableContainer.add (std::move (ct));
noncopyableContainer.add (std::move (nct));
}
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("add multiple");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
for (int i = 4; i < 7; ++i)
referenceContainer.push_back ({ -i });
copyableContainer.add (CopyableType (-4), CopyableType (-5), CopyableType (-6));
noncopyableContainer.add (NoncopyableType (-4), NoncopyableType (-5), NoncopyableType (-6));
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("add array from a pointer");
{
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
std::vector<CopyableType> copyableData = { 3, 4, 5 };
std::vector<NoncopyableType> noncopyableData = { 3, 4, 5 };
copyableContainer.addArray (copyableData.data(), (int) copyableData.size());
noncopyableContainer.addArray (noncopyableData.data(), (int) noncopyableData.size());
checkEqual (copyableContainer, noncopyableContainer, copyableData);
}
beginTest ("add array from a pointer of a different type");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
std::vector<float> floatData = { 1.4f, 2.5f, 3.6f };
for (auto f : floatData)
referenceContainer.push_back ({ f });
copyableContainer.addArray (floatData.data(), (int) floatData.size());
noncopyableContainer.addArray (floatData.data(), (int) floatData.size());
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("add array from initilizer list");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
std::initializer_list<CopyableType> ilct { { 3 }, { 4 }, { 5 } };
std::initializer_list<NoncopyableType> ilnct { { 3 }, { 4 }, { 5 } };
for (auto v : ilct)
referenceContainer.push_back ({ v });
copyableContainer.addArray (ilct);
noncopyableContainer.addArray (ilnct);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("add array from containers");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
addData (referenceContainer, copyableContainer, noncopyableContainer, 5);
std::vector<CopyableType> referenceContainerCopy (referenceContainer);
std::vector<NoncopyableType> noncopyableReferenceContainerCopy;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainerCopy;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainerCopy;
for (auto& v : referenceContainerCopy)
noncopyableReferenceContainerCopy.push_back ({ v.getValue() });
for (size_t i = 0; i < referenceContainerCopy.size(); ++i)
{
auto value = referenceContainerCopy[i].getValue();
copyableContainerCopy.add ({ value });
noncopyableContainerCopy.add ({ value });
}
// From self-types
copyableContainer.addArray (copyableContainerCopy);
noncopyableContainer.addArray (noncopyableContainerCopy);
for (auto v : referenceContainerCopy)
referenceContainer.push_back (v);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
// From std containers
copyableContainer.addArray (referenceContainerCopy);
noncopyableContainer.addArray (noncopyableReferenceContainerCopy);
for (auto v : referenceContainerCopy)
referenceContainer.push_back (v);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
// From std containers with offset
int offset = 5;
copyableContainer.addArray (referenceContainerCopy, offset);
noncopyableContainer.addArray (noncopyableReferenceContainerCopy, offset);
for (size_t i = 5; i < referenceContainerCopy.size(); ++i)
referenceContainer.push_back (referenceContainerCopy[i]);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("insert");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
addData (referenceContainer, copyableContainer, noncopyableContainer, 8);
referenceContainer.insert (referenceContainer.begin(), -4);
copyableContainer.insert (0, -4, 1);
noncopyableContainer.insert (0, -4, 1);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
for (int i = 0; i < 3; ++i)
referenceContainer.insert (referenceContainer.begin() + 1, -3);
copyableContainer.insert (1, -3, 3);
noncopyableContainer.insert (1, -3, 3);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
for (int i = 0; i < 50; ++i)
referenceContainer.insert (referenceContainer.end() - 1, -9);
copyableContainer.insert (copyableContainer.size() - 2, -9, 50);
noncopyableContainer.insert (noncopyableContainer.size() - 2, -9, 50);
}
beginTest ("insert array");
{
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
std::vector<CopyableType> copyableData = { 3, 4, 5, 6, 7, 8 };
std::vector<NoncopyableType> noncopyableData = { 3, 4, 5, 6, 7, 8 };
std::vector<CopyableType> referenceContainer { copyableData };
copyableContainer.insertArray (0, copyableData.data(), (int) copyableData.size());
noncopyableContainer.insertArray (0, noncopyableData.data(), (int) noncopyableData.size());
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
int insertPos = copyableContainer.size() - 1;
for (auto it = copyableData.end(); it != copyableData.begin(); --it)
referenceContainer.insert (referenceContainer.begin() + insertPos, CopyableType (*(it - 1)));
copyableContainer.insertArray (insertPos, copyableData.data(), (int) copyableData.size());
noncopyableContainer.insertArray (insertPos, noncopyableData.data(), (int) noncopyableData.size());
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("remove");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
addData (referenceContainer, copyableContainer, noncopyableContainer, 17);
for (int i = 0; i < 4; ++i)
{
referenceContainer.erase (referenceContainer.begin() + i);
copyableContainer.removeElements (i, 1);
noncopyableContainer.removeElements (i, 1);
}
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
addData (referenceContainer, copyableContainer, noncopyableContainer, 17);
int blockSize = 3;
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < blockSize; ++j)
referenceContainer.erase (referenceContainer.begin() + i);
copyableContainer.removeElements (i, blockSize);
noncopyableContainer.removeElements (i, blockSize);
}
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
auto numToRemove = copyableContainer.size() - 2;
for (int i = 0; i < numToRemove; ++i)
referenceContainer.erase (referenceContainer.begin() + 1);
copyableContainer.removeElements (1, numToRemove);
noncopyableContainer.removeElements (1, numToRemove);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
beginTest ("move");
{
std::vector<CopyableType> referenceContainer;
ArrayBase<CopyableType, DummyCriticalSection> copyableContainer;
ArrayBase<NoncopyableType, DummyCriticalSection> noncopyableContainer;
addData (referenceContainer, copyableContainer, noncopyableContainer, 6);
std::vector<std::pair<int, int>> testValues;
testValues.emplace_back (2, 4);
testValues.emplace_back (0, 5);
testValues.emplace_back (4, 1);
testValues.emplace_back (5, 0);
for (auto p : testValues)
{
if (p.second > p.first)
std::rotate (referenceContainer.begin() + p.first,
referenceContainer.begin() + p.first + 1,
referenceContainer.begin() + p.second + 1);
else
std::rotate (referenceContainer.begin() + p.second,
referenceContainer.begin() + p.first,
referenceContainer.begin() + p.first + 1);
copyableContainer.move (p.first, p.second);
noncopyableContainer.move (p.first, p.second);
checkEqual (copyableContainer, noncopyableContainer, referenceContainer);
}
}
beginTest ("After converting move construction, ownership is transferred");
{
Derived obj;
ArrayBase<Derived*, DummyCriticalSection> derived;
derived.setAllocatedSize (5);
derived.add (&obj);
ArrayBase<Base*, DummyCriticalSection> base { std::move (derived) };
expectEquals (base.capacity(), 5);
expectEquals (base.size(), 1);
expect (base.getFirst() == &obj);
expectEquals (derived.capacity(), 0);
expectEquals (derived.size(), 0);
expect (derived.data() == nullptr);
}
beginTest ("After converting move assignment, ownership is transferred");
{
Derived obj;
ArrayBase<Derived*, DummyCriticalSection> derived;
derived.setAllocatedSize (5);
derived.add (&obj);
ArrayBase<Base*, DummyCriticalSection> base;
base = std::move (derived);
expectEquals (base.capacity(), 5);
expectEquals (base.size(), 1);
expect (base.getFirst() == &obj);
expectEquals (derived.capacity(), 0);
expectEquals (derived.size(), 0);
expect (derived.data() == nullptr);
}
}
private:
struct Base
{
virtual ~Base() = default;
};
struct Derived : Base
{
};
static void addData (std::vector<CopyableType>& referenceContainer,
ArrayBase<CopyableType, DummyCriticalSection>& copyableContainer,
ArrayBase<NoncopyableType, DummyCriticalSection>& NoncopyableContainer,
int numValues)
{
for (int i = 0; i < numValues; ++i)
{
referenceContainer.push_back ({ i });
copyableContainer.add ({ i });
NoncopyableContainer.add ({ i });
}
}
template<typename A, typename B>
void checkEqual (const ArrayBase<A, DummyCriticalSection>& a,
const ArrayBase<B, DummyCriticalSection>& b)
{
expectEquals ((int) a.size(), (int) b.size());
for (int i = 0; i < (int) a.size(); ++i)
expect (a[i] == b[i]);
}
template<typename A, typename B>
void checkEqual (ArrayBase<A, DummyCriticalSection>& a,
std::vector<B>& b)
{
expectEquals ((int) a.size(), (int) b.size());
for (int i = 0; i < (int) a.size(); ++i)
expect (a[i] == b[(size_t) i]);
}
template<typename A, typename B, typename C>
void checkEqual (ArrayBase<A, DummyCriticalSection>& a,
ArrayBase<B, DummyCriticalSection>& b,
std::vector<C>& c)
{
checkEqual (a, b);
checkEqual (a, c);
checkEqual (b, c);
}
};
static ArrayBaseTests arrayBaseTests;
#endif
} // namespace juce

View File

@ -0,0 +1,596 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
/**
A basic object container.
This class isn't really for public use - it's used by the other
array classes, but might come in handy for some purposes.
It inherits from a critical section class to allow the arrays to use
the "empty base class optimisation" pattern to reduce their footprint.
@see Array, OwnedArray, ReferenceCountedArray
@tags{Core}
*/
template <class ElementType, class TypeOfCriticalSectionToUse>
class ArrayBase : public TypeOfCriticalSectionToUse
{
private:
using ParameterType = typename TypeHelpers::ParameterType<ElementType>::type;
template <class OtherElementType, class OtherCriticalSection>
using AllowConversion = typename std::enable_if<! std::is_same<std::tuple<ElementType, TypeOfCriticalSectionToUse>,
std::tuple<OtherElementType, OtherCriticalSection>>::value>::type;
public:
//==============================================================================
ArrayBase() = default;
~ArrayBase()
{
clear();
}
ArrayBase (ArrayBase&& other) noexcept
: elements (std::move (other.elements)),
numAllocated (other.numAllocated),
numUsed (other.numUsed)
{
other.numAllocated = 0;
other.numUsed = 0;
}
ArrayBase& operator= (ArrayBase&& other) noexcept
{
if (this != &other)
{
auto tmp (std::move (other));
swapWith (tmp);
}
return *this;
}
/** Converting move constructor.
Only enabled when the other array has a different type to this one.
If you see a compile error here, it's probably because you're attempting a conversion that
HeapBlock won't allow.
*/
template <class OtherElementType,
class OtherCriticalSection,
typename = AllowConversion<OtherElementType, OtherCriticalSection>>
ArrayBase (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
: elements (std::move (other.elements)),
numAllocated (other.numAllocated),
numUsed (other.numUsed)
{
other.numAllocated = 0;
other.numUsed = 0;
}
/** Converting move assignment operator.
Only enabled when the other array has a different type to this one.
If you see a compile error here, it's probably because you're attempting a conversion that
HeapBlock won't allow.
*/
template <class OtherElementType,
class OtherCriticalSection,
typename = AllowConversion<OtherElementType, OtherCriticalSection>>
ArrayBase& operator= (ArrayBase<OtherElementType, OtherCriticalSection>&& other) noexcept
{
// No need to worry about assignment to *this, because 'other' must be of a different type.
elements = std::move (other.elements);
numAllocated = other.numAllocated;
numUsed = other.numUsed;
other.numAllocated = 0;
other.numUsed = 0;
return *this;
}
//==============================================================================
template <class OtherArrayType>
bool operator== (const OtherArrayType& other) const noexcept
{
if (size() != (int) other.size())
return false;
auto* e = begin();
for (auto& o : other)
if (! (*e++ == o))
return false;
return true;
}
template <class OtherArrayType>
bool operator!= (const OtherArrayType& other) const noexcept
{
return ! operator== (other);
}
//==============================================================================
inline ElementType& operator[] (const int index) const noexcept
{
jassert (elements != nullptr);
jassert (isPositiveAndBelow (index, numUsed));
return elements[index];
}
inline ElementType getValueWithDefault (const int index) const noexcept
{
return isPositiveAndBelow (index, numUsed) ? elements[index] : ElementType();
}
inline ElementType getFirst() const noexcept
{
return numUsed > 0 ? elements[0] : ElementType();
}
inline ElementType getLast() const noexcept
{
return numUsed > 0 ? elements[numUsed - 1] : ElementType();
}
//==============================================================================
inline ElementType* begin() const noexcept
{
return elements;
}
inline ElementType* end() const noexcept
{
return elements + numUsed;
}
inline ElementType* data() const noexcept
{
return elements;
}
inline int size() const noexcept
{
return numUsed;
}
inline int capacity() const noexcept
{
return numAllocated;
}
//==============================================================================
void setAllocatedSize (int numElements)
{
jassert (numElements >= numUsed);
if (numAllocated != numElements)
{
if (numElements > 0)
setAllocatedSizeInternal (numElements);
else
elements.free();
}
numAllocated = numElements;
}
void ensureAllocatedSize (int minNumElements)
{
if (minNumElements > numAllocated)
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
jassert (numAllocated <= 0 || elements != nullptr);
}
void shrinkToNoMoreThan (int maxNumElements)
{
if (maxNumElements < numAllocated)
setAllocatedSize (maxNumElements);
}
void clear()
{
for (int i = 0; i < numUsed; ++i)
elements[i].~ElementType();
numUsed = 0;
}
//==============================================================================
void swapWith (ArrayBase& other) noexcept
{
elements.swapWith (other.elements);
std::swap (numAllocated, other.numAllocated);
std::swap (numUsed, other.numUsed);
}
//==============================================================================
void add (const ElementType& newElement)
{
checkSourceIsNotAMember (&newElement);
ensureAllocatedSize (numUsed + 1);
addAssumingCapacityIsReady (newElement);
}
void add (ElementType&& newElement)
{
checkSourceIsNotAMember (&newElement);
ensureAllocatedSize (numUsed + 1);
addAssumingCapacityIsReady (std::move (newElement));
}
template <typename... OtherElements>
void add (const ElementType& firstNewElement, OtherElements... otherElements)
{
checkSourceIsNotAMember (&firstNewElement);
ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
addAssumingCapacityIsReady (firstNewElement, otherElements...);
}
template <typename... OtherElements>
void add (ElementType&& firstNewElement, OtherElements... otherElements)
{
checkSourceIsNotAMember (&firstNewElement);
ensureAllocatedSize (numUsed + 1 + (int) sizeof... (otherElements));
addAssumingCapacityIsReady (std::move (firstNewElement), otherElements...);
}
//==============================================================================
template <typename Type>
void addArray (const Type* elementsToAdd, int numElementsToAdd)
{
ensureAllocatedSize (numUsed + numElementsToAdd);
addArrayInternal (elementsToAdd, numElementsToAdd);
numUsed += numElementsToAdd;
}
template <typename TypeToCreateFrom>
void addArray (const std::initializer_list<TypeToCreateFrom>& items)
{
ensureAllocatedSize (numUsed + (int) items.size());
for (auto& item : items)
new (elements + numUsed++) ElementType (item);
}
template <class OtherArrayType>
void addArray (const OtherArrayType& arrayToAddFrom)
{
jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
ensureAllocatedSize (numUsed + (int) arrayToAddFrom.size());
for (auto& e : arrayToAddFrom)
addAssumingCapacityIsReady (e);
}
template <class OtherArrayType>
typename std::enable_if<! std::is_pointer<OtherArrayType>::value, int>::type
addArray (const OtherArrayType& arrayToAddFrom,
int startIndex, int numElementsToAdd = -1)
{
jassert ((const void*) this != (const void*) &arrayToAddFrom); // can't add from our own elements!
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > (int) arrayToAddFrom.size())
numElementsToAdd = (int) arrayToAddFrom.size() - startIndex;
addArray (arrayToAddFrom.data() + startIndex, numElementsToAdd);
return numElementsToAdd;
}
//==============================================================================
void insert (int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt)
{
checkSourceIsNotAMember (&newElement);
auto* space = createInsertSpace (indexToInsertAt, numberOfTimesToInsertIt);
for (int i = 0; i < numberOfTimesToInsertIt; ++i)
new (space++) ElementType (newElement);
numUsed += numberOfTimesToInsertIt;
}
void insertArray (int indexToInsertAt, const ElementType* newElements, int numberOfElements)
{
auto* space = createInsertSpace (indexToInsertAt, numberOfElements);
for (int i = 0; i < numberOfElements; ++i)
new (space++) ElementType (*(newElements++));
numUsed += numberOfElements;
}
//==============================================================================
void removeElements (int indexToRemoveAt, int numElementsToRemove)
{
jassert (indexToRemoveAt >= 0);
jassert (numElementsToRemove >= 0);
jassert (indexToRemoveAt + numElementsToRemove <= numUsed);
if (numElementsToRemove > 0)
{
removeElementsInternal (indexToRemoveAt, numElementsToRemove);
numUsed -= numElementsToRemove;
}
}
//==============================================================================
void swap (int index1, int index2)
{
if (isPositiveAndBelow (index1, numUsed)
&& isPositiveAndBelow (index2, numUsed))
{
std::swap (elements[index1],
elements[index2]);
}
}
//==============================================================================
void move (int currentIndex, int newIndex) noexcept
{
if (isPositiveAndBelow (currentIndex, numUsed))
{
if (! isPositiveAndBelow (newIndex, numUsed))
newIndex = numUsed - 1;
moveInternal (currentIndex, newIndex);
}
}
private:
//==============================================================================
template <typename T>
#if defined(__GNUC__) && __GNUC__ < 5 && ! defined(__clang__)
using IsTriviallyCopyable = std::is_scalar<T>;
#else
using IsTriviallyCopyable = std::is_trivially_copyable<T>;
#endif
template <typename T>
using TriviallyCopyableVoid = typename std::enable_if<IsTriviallyCopyable<T>::value, void>::type;
template <typename T>
using NonTriviallyCopyableVoid = typename std::enable_if<! IsTriviallyCopyable<T>::value, void>::type;
//==============================================================================
template <typename T = ElementType>
TriviallyCopyableVoid<T> addArrayInternal (const ElementType* otherElements, int numElements)
{
memcpy (elements + numUsed, otherElements, (size_t) numElements * sizeof (ElementType));
}
template <typename Type, typename T = ElementType>
TriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
{
auto* start = elements + numUsed;
while (--numElements >= 0)
new (start++) ElementType (*(otherElements++));
}
template <typename Type, typename T = ElementType>
NonTriviallyCopyableVoid<T> addArrayInternal (const Type* otherElements, int numElements)
{
auto* start = elements + numUsed;
while (--numElements >= 0)
new (start++) ElementType (*(otherElements++));
}
//==============================================================================
template <typename T = ElementType>
TriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
{
elements.realloc ((size_t) numElements);
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> setAllocatedSizeInternal (int numElements)
{
HeapBlock<ElementType> newElements (numElements);
for (int i = 0; i < numUsed; ++i)
{
new (newElements + i) ElementType (std::move (elements[i]));
elements[i].~ElementType();
}
elements = std::move (newElements);
}
//==============================================================================
ElementType* createInsertSpace (int indexToInsertAt, int numElements)
{
ensureAllocatedSize (numUsed + numElements);
if (! isPositiveAndBelow (indexToInsertAt, numUsed))
return elements + numUsed;
createInsertSpaceInternal (indexToInsertAt, numElements);
return elements + indexToInsertAt;
}
template <typename T = ElementType>
TriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
{
auto* start = elements + indexToInsertAt;
auto numElementsToShift = numUsed - indexToInsertAt;
memmove (start + numElements, start, (size_t) numElementsToShift * sizeof (ElementType));
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> createInsertSpaceInternal (int indexToInsertAt, int numElements)
{
auto* end = elements + numUsed;
auto* newEnd = end + numElements;
auto numElementsToShift = numUsed - indexToInsertAt;
for (int i = 0; i < numElementsToShift; ++i)
{
new (--newEnd) ElementType (std::move (*(--end)));
end->~ElementType();
}
}
//==============================================================================
template <typename T = ElementType>
TriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
{
auto* start = elements + indexToRemoveAt;
auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
memmove (start, start + numElementsToRemove, (size_t) numElementsToShift * sizeof (ElementType));
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> removeElementsInternal (int indexToRemoveAt, int numElementsToRemove)
{
auto numElementsToShift = numUsed - (indexToRemoveAt + numElementsToRemove);
auto* destination = elements + indexToRemoveAt;
auto* source = destination + numElementsToRemove;
for (int i = 0; i < numElementsToShift; ++i)
moveAssignElement (destination++, std::move (*(source++)));
for (int i = 0; i < numElementsToRemove; ++i)
(destination++)->~ElementType();
}
//==============================================================================
template <typename T = ElementType>
TriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
{
char tempCopy[sizeof (ElementType)];
memcpy (tempCopy, elements + currentIndex, sizeof (ElementType));
if (newIndex > currentIndex)
{
memmove (elements + currentIndex,
elements + currentIndex + 1,
sizeof (ElementType) * (size_t) (newIndex - currentIndex));
}
else
{
memmove (elements + newIndex + 1,
elements + newIndex,
sizeof (ElementType) * (size_t) (currentIndex - newIndex));
}
memcpy (elements + newIndex, tempCopy, sizeof (ElementType));
}
template <typename T = ElementType>
NonTriviallyCopyableVoid<T> moveInternal (int currentIndex, int newIndex) noexcept
{
auto* e = elements + currentIndex;
ElementType tempCopy (std::move (*e));
auto delta = newIndex - currentIndex;
if (delta > 0)
{
for (int i = 0; i < delta; ++i)
{
moveAssignElement (e, std::move (*(e + 1)));
++e;
}
}
else
{
for (int i = 0; i < -delta; ++i)
{
moveAssignElement (e, std::move (*(e - 1)));
--e;
}
}
moveAssignElement (e, std::move (tempCopy));
}
//==============================================================================
void addAssumingCapacityIsReady (const ElementType& element) { new (elements + numUsed++) ElementType (element); }
void addAssumingCapacityIsReady (ElementType&& element) { new (elements + numUsed++) ElementType (std::move (element)); }
template <typename... OtherElements>
void addAssumingCapacityIsReady (const ElementType& firstNewElement, OtherElements... otherElements)
{
addAssumingCapacityIsReady (firstNewElement);
addAssumingCapacityIsReady (otherElements...);
}
template <typename... OtherElements>
void addAssumingCapacityIsReady (ElementType&& firstNewElement, OtherElements... otherElements)
{
addAssumingCapacityIsReady (std::move (firstNewElement));
addAssumingCapacityIsReady (otherElements...);
}
//==============================================================================
template <typename T = ElementType>
typename std::enable_if<std::is_move_assignable<T>::value, void>::type
moveAssignElement (ElementType* destination, ElementType&& source)
{
*destination = std::move (source);
}
template <typename T = ElementType>
typename std::enable_if<! std::is_move_assignable<T>::value, void>::type
moveAssignElement (ElementType* destination, ElementType&& source)
{
destination->~ElementType();
new (destination) ElementType (std::move (source));
}
void checkSourceIsNotAMember (const ElementType* element)
{
// when you pass a reference to an existing element into a method like add() which
// may need to reallocate the array to make more space, the incoming reference may
// be deleted indirectly during the reallocation operation! To work around this,
// make a local copy of the item you're trying to add (and maybe use std::move to
// move it into the add() method to avoid any extra overhead)
jassert (element < begin() || element >= end());
ignoreUnused (element);
}
//==============================================================================
HeapBlock<ElementType> elements;
int numAllocated = 0, numUsed = 0;
template <class OtherElementType, class OtherCriticalSection>
friend class ArrayBase;
JUCE_DECLARE_NON_COPYABLE (ArrayBase)
};
} // namespace juce

View File

@ -42,7 +42,7 @@ public:
//==============================================================================
DynamicObject();
DynamicObject (const DynamicObject&);
~DynamicObject();
~DynamicObject() override;
using Ptr = ReferenceCountedObjectPtr<DynamicObject>;

View File

@ -120,7 +120,7 @@ public:
*/
explicit HashMap (int numberOfSlots = defaultHashTableSize,
HashFunctionType hashFunction = HashFunctionType())
: hashFunctionToUse (hashFunction), totalNumItems (0)
: hashFunctionToUse (hashFunction)
{
hashSlots.insertMultiple (0, nullptr, numberOfSlots);
}
@ -354,7 +354,7 @@ public:
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; }
/** Returns the type of scoped lock to use for locking this array */
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
private:
//==============================================================================
@ -388,7 +388,7 @@ public:
}
@endcode
The order in which items are iterated bears no resemblence to the order in which
The order in which items are iterated bears no resemblance to the order in which
they were originally added!
Obviously as soon as you call any non-const methods on the original hash-map, any
@ -479,7 +479,7 @@ private:
HashFunctionType hashFunctionToUse;
Array<HashEntry*> hashSlots;
int totalNumItems;
int totalNumItems = 0;
TypeOfCriticalSectionToUse lock;
int generateHashFor (KeyTypeParameter key, int numSlots) const

View File

@ -70,10 +70,10 @@ class ListenerList
public:
//==============================================================================
/** Creates an empty list. */
ListenerList() {}
ListenerList() = default;
/** Destructor. */
~ListenerList() {}
~ListenerList() = default;
//==============================================================================
/** Adds a listener to the list.
@ -101,7 +101,7 @@ public:
/** Returns the number of registered listeners. */
int size() const noexcept { return listeners.size(); }
/** Returns true if any listeners are registered. */
/** Returns true if no listeners are registered, false otherwise. */
bool isEmpty() const noexcept { return listeners.isEmpty(); }
/** Clears the list. */
@ -194,7 +194,7 @@ public:
: list (listToIterate), index (listToIterate.size())
{}
~Iterator() noexcept {}
~Iterator() = default;
//==============================================================================
bool next() noexcept

View File

@ -30,24 +30,24 @@ NamedValueSet::NamedValue::NamedValue (const Identifier& n, const var& v) : nam
NamedValueSet::NamedValue::NamedValue (const NamedValue& other) : NamedValue (other.name, other.value) {}
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
: NamedValue (static_cast<Identifier&&> (other.name),
static_cast<var&&> (other.value))
: NamedValue (std::move (other.name),
std::move (other.value))
{}
NamedValueSet::NamedValue::NamedValue (const Identifier& n, var&& v) noexcept
: name (n), value (static_cast<var&&> (v))
: name (n), value (std::move (v))
{
}
NamedValueSet::NamedValue::NamedValue (Identifier&& n, var&& v) noexcept
: name (static_cast<Identifier&&> (n)),
value (static_cast<var&&> (v))
: name (std::move (n)),
value (std::move (v))
{}
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
{
name = static_cast<Identifier&&> (other.name);
value = static_cast<var&&> (other.value);
name = std::move (other.name);
value = std::move (other.value);
return *this;
}
@ -59,7 +59,14 @@ NamedValueSet::NamedValueSet() noexcept {}
NamedValueSet::~NamedValueSet() noexcept {}
NamedValueSet::NamedValueSet (const NamedValueSet& other) : values (other.values) {}
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept : values (static_cast<Array<NamedValue>&&> (other.values)) {}
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
: values (std::move (other.values)) {}
NamedValueSet::NamedValueSet (std::initializer_list<NamedValue> list)
: values (std::move (list))
{
}
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
{
@ -156,11 +163,11 @@ bool NamedValueSet::set (const Identifier& name, var&& newValue)
if (v->equalsWithSameType (newValue))
return false;
*v = static_cast<var&&> (newValue);
*v = std::move (newValue);
return true;
}
values.add ({ name, static_cast<var&&> (newValue) });
values.add ({ name, std::move (newValue) });
return true;
}

View File

@ -34,23 +34,6 @@ namespace juce
class JUCE_API NamedValueSet
{
public:
/** Creates an empty set. */
NamedValueSet() noexcept;
NamedValueSet (const NamedValueSet&);
NamedValueSet (NamedValueSet&&) noexcept;
NamedValueSet& operator= (const NamedValueSet&);
NamedValueSet& operator= (NamedValueSet&&) noexcept;
/** Destructor. */
~NamedValueSet() noexcept;
/** Two NamedValueSets are considered equal if they contain all the same key/value
pairs, regardless of the order.
*/
bool operator== (const NamedValueSet&) const noexcept;
bool operator!= (const NamedValueSet&) const noexcept;
//==============================================================================
/** Structure for a named var object */
struct JUCE_API NamedValue
@ -73,6 +56,27 @@ public:
var value;
};
//==============================================================================
/** Creates an empty set. */
NamedValueSet() noexcept;
NamedValueSet (const NamedValueSet&);
NamedValueSet (NamedValueSet&&) noexcept;
NamedValueSet& operator= (const NamedValueSet&);
NamedValueSet& operator= (NamedValueSet&&) noexcept;
/** Creates a NamedValueSet from a list of names and properties. */
NamedValueSet (std::initializer_list<NamedValue>);
/** Destructor. */
~NamedValueSet() noexcept;
/** Two NamedValueSets are considered equal if they contain all the same key/value
pairs, regardless of the order.
*/
bool operator== (const NamedValueSet&) const noexcept;
bool operator!= (const NamedValueSet&) const noexcept;
const NamedValueSet::NamedValue* begin() const noexcept { return values.begin(); }
const NamedValueSet::NamedValue* end() const noexcept { return values.end(); }
@ -125,6 +129,8 @@ public:
Do not use this method unless you really need access to the internal var object
for some reason - for normal reading and writing always prefer operator[]() and set().
Also note that the pointer returned may become invalid as soon as any subsequent
methods are called on the NamedValueSet.
*/
var* getVarPointer (const Identifier& name) const noexcept;
@ -135,6 +141,8 @@ public:
/** Returns the value of the item at a given index.
The index must be between 0 and size() - 1, or this will return a nullptr
Also note that the pointer returned may become invalid as soon as any subsequent
methods are called on the NamedValueSet.
*/
var* getVarPointerAt (int index) const noexcept;

View File

@ -0,0 +1,66 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#if JUCE_UNIT_TESTS
static struct OwnedArrayTest : public UnitTest
{
OwnedArrayTest() : UnitTest { "OwnedArray" } {}
struct Base
{
virtual ~Base() = default;
};
struct Derived : Base
{
};
void runTest() override
{
beginTest ("After converting move construction, ownership is transferred");
{
OwnedArray<Derived> derived { new Derived{}, new Derived{}, new Derived{} };
OwnedArray<Base> base { std::move (derived) };
expectEquals (base.size(), 3);
expectEquals (derived.size(), 0);
}
beginTest ("After converting move assignment, ownership is transferred");
{
OwnedArray<Base> base;
base = OwnedArray<Derived> { new Derived{}, new Derived{}, new Derived{} };
expectEquals (base.size(), 3);
}
}
} ownedArrayTest;
#endif
}

View File

@ -52,9 +52,7 @@ class OwnedArray
public:
//==============================================================================
/** Creates an empty array. */
OwnedArray() noexcept
{
}
OwnedArray() = default;
/** Deletes the array and also deletes any objects inside it.
@ -68,10 +66,8 @@ public:
/** Move constructor. */
OwnedArray (OwnedArray&& other) noexcept
: data (static_cast<ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data)),
numUsed (other.numUsed)
: values (std::move (other.values))
{
other.numUsed = 0;
}
/** Creates an array from a list of objects. */
@ -85,10 +81,24 @@ public:
{
const ScopedLockType lock (getLock());
deleteAllObjects();
values = std::move (other.values);
return *this;
}
data = static_cast<ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data);
numUsed = other.numUsed;
other.numUsed = 0;
/** Converting move constructor. */
template <class OtherObjectClass, class OtherCriticalSection>
OwnedArray (OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
: values (std::move (other.values))
{
}
/** Converting move assignment operator. */
template <class OtherObjectClass, class OtherCriticalSection>
OwnedArray& operator= (OwnedArray<OtherObjectClass, OtherCriticalSection>&& other) noexcept
{
const ScopedLockType lock (getLock());
deleteAllObjects();
values = std::move (other.values);
return *this;
}
@ -97,12 +107,8 @@ public:
void clear (bool deleteObjects = true)
{
const ScopedLockType lock (getLock());
if (deleteObjects)
deleteAllObjects();
data.setAllocatedSize (0);
numUsed = 0;
clearQuick (deleteObjects);
values.setAllocatedSize (0);
}
//==============================================================================
@ -113,8 +119,8 @@ public:
if (deleteObjects)
deleteAllObjects();
numUsed = 0;
else
values.clear();
}
//==============================================================================
@ -123,7 +129,7 @@ public:
*/
inline int size() const noexcept
{
return numUsed;
return values.size();
}
/** Returns true if the array is empty, false otherwise. */
@ -143,13 +149,7 @@ public:
inline ObjectClass* operator[] (const int index) const noexcept
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (index, numUsed))
{
jassert (data.elements != nullptr);
return data.elements[index];
}
return nullptr;
return values.getValueWithDefault (index);
}
/** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
@ -160,8 +160,7 @@ public:
inline ObjectClass* getUnchecked (const int index) const noexcept
{
const ScopedLockType lock (getLock());
jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
return data.elements[index];
return values[index];
}
/** Returns a pointer to the first object in the array.
@ -172,14 +171,7 @@ public:
inline ObjectClass* getFirst() const noexcept
{
const ScopedLockType lock (getLock());
if (numUsed > 0)
{
jassert (data.elements != nullptr);
return data.elements[0];
}
return nullptr;
return values.getFirst();
}
/** Returns a pointer to the last object in the array.
@ -190,14 +182,7 @@ public:
inline ObjectClass* getLast() const noexcept
{
const ScopedLockType lock (getLock());
if (numUsed > 0)
{
jassert (data.elements != nullptr);
return data.elements[numUsed - 1];
}
return nullptr;
return values.getLast();
}
/** Returns a pointer to the actual array data.
@ -206,7 +191,7 @@ public:
*/
inline ObjectClass** getRawDataPointer() noexcept
{
return data.elements;
return values.begin();
}
//==============================================================================
@ -215,7 +200,7 @@ public:
*/
inline ObjectClass** begin() const noexcept
{
return data.elements;
return values.begin();
}
/** Returns a pointer to the element which follows the last element in the array.
@ -223,12 +208,15 @@ public:
*/
inline ObjectClass** end() const noexcept
{
#if JUCE_DEBUG
if (data.elements == nullptr || numUsed <= 0) // (to keep static analysers happy)
return data.elements;
#endif
return values.end();
}
return data.elements + numUsed;
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ObjectClass** data() const noexcept
{
return begin();
}
//==============================================================================
@ -240,12 +228,11 @@ public:
int indexOf (const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock (getLock());
auto** e = data.elements.get();
auto** end_ = e + numUsed;
auto** e = values.begin();
for (; e != end_; ++e)
for (; e != values.end(); ++e)
if (objectToLookFor == *e)
return static_cast<int> (e - data.elements.get());
return static_cast<int> (e - values.begin());
return -1;
}
@ -258,10 +245,9 @@ public:
bool contains (const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock (getLock());
auto** e = data.elements.get();
auto** end_ = e + numUsed;
auto** e = values.begin();
for (; e != end_; ++e)
for (; e != values.end(); ++e)
if (objectToLookFor == *e)
return true;
@ -284,9 +270,7 @@ public:
ObjectClass* add (ObjectClass* newObject) noexcept
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
data.elements[numUsed++] = newObject;
values.add (newObject);
return newObject;
}
@ -310,25 +294,8 @@ public:
*/
ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject) noexcept
{
if (indexToInsertAt < 0)
return add (newObject);
const ScopedLockType lock (getLock());
if (indexToInsertAt > numUsed)
indexToInsertAt = numUsed;
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
auto** e = data.elements + indexToInsertAt;
auto numToMove = numUsed - indexToInsertAt;
if (numToMove > 0)
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
*e = newObject;
++numUsed;
values.insert (indexToInsertAt, newObject, 1);
return newObject;
}
@ -351,24 +318,7 @@ public:
if (numberOfElements > 0)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + numberOfElements);
auto* insertPos = data.elements.get();
if (isPositiveAndBelow (indexToInsertAt, numUsed))
{
insertPos += indexToInsertAt;
auto numberToMove = (size_t) (numUsed - indexToInsertAt);
memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ObjectClass*));
}
else
{
insertPos += numUsed;
}
numUsed += numberOfElements;
while (--numberOfElements >= 0)
*insertPos++ = *newObjects++;
values.insertArray (indexToInsertAt, newObjects, numberOfElements);
}
}
@ -413,22 +363,21 @@ public:
{
const ScopedLockType lock (getLock());
if (indexToChange < numUsed)
if (indexToChange < values.size())
{
if (deleteOldElement)
{
toDelete.reset (data.elements[indexToChange]);
toDelete.reset (values[indexToChange]);
if (toDelete.get() == newObject)
toDelete.release();
}
data.elements[indexToChange] = newObject;
values[indexToChange] = newObject;
}
else
{
data.ensureAllocatedSize (numUsed + 1);
data.elements[numUsed++] = newObject;
values.add (newObject);
}
}
}
@ -457,24 +406,7 @@ public:
{
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
const ScopedLockType lock2 (getLock());
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
numElementsToAdd = arrayToAddFrom.size() - startIndex;
data.ensureAllocatedSize (numUsed + numElementsToAdd);
jassert (numElementsToAdd <= 0 || data.elements != nullptr);
while (--numElementsToAdd >= 0)
{
data.elements[numUsed] = arrayToAddFrom.getUnchecked (startIndex++);
++numUsed;
}
values.addArray (arrayToAddFrom, startIndex, numElementsToAdd);
}
/** Adds elements from another array to the end of this array. */
@ -482,13 +414,7 @@ public:
void addArray (const std::initializer_list<OtherArrayType>& items)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + (int) items.size());
for (auto* item : items)
{
data.elements[numUsed] = item;
++numUsed;
}
values.addArray (items);
}
/** Adds copies of the elements in another array to the end of this array.
@ -522,11 +448,11 @@ public:
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
numElementsToAdd = arrayToAddFrom.size() - startIndex;
data.ensureAllocatedSize (numUsed + numElementsToAdd);
jassert (numElementsToAdd <= 0 || data.elements != nullptr);
jassert (numElementsToAdd >= 0);
values.ensureAllocatedSize (values.size() + numElementsToAdd);
while (--numElementsToAdd >= 0)
data.elements[numUsed++] = createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++));
values.add (createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++)));
}
/** Inserts a new object into the array assuming that the array is sorted.
@ -544,10 +470,12 @@ public:
template <class ElementComparator>
int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept
{
ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused (comparator);
const ScopedLockType lock (getLock());
const int index = findInsertIndexInSortedArray (comparator, data.elements.get(), newObject, 0, numUsed);
const int index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
insert (index, newObject);
return index;
}
@ -567,13 +495,16 @@ public:
template <typename ElementComparator>
int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const noexcept
{
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused (comparator);
const ScopedLockType lock (getLock());
int s = 0, e = numUsed;
int s = 0, e = values.size();
while (s < e)
{
if (comparator.compareElements (objectToLookFor, data.elements[s]) == 0)
if (comparator.compareElements (objectToLookFor, values[s]) == 0)
return s;
auto halfway = (s + e) / 2;
@ -581,7 +512,7 @@ public:
if (halfway == s)
break;
if (comparator.compareElements (objectToLookFor, data.elements[halfway]) >= 0)
if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
s = halfway;
else
e = halfway;
@ -608,22 +539,18 @@ public:
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
if (isPositiveAndBelow (indexToRemove, values.size()))
{
auto** e = data.elements + indexToRemove;
auto** e = values.begin() + indexToRemove;
if (deleteObject)
toDelete.reset (*e);
--numUsed;
auto numToShift = numUsed - indexToRemove;
if (numToShift > 0)
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
values.removeElements (indexToRemove, 1);
}
}
if ((numUsed << 1) < data.numAllocated)
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
@ -641,18 +568,13 @@ public:
ObjectClass* removedItem = nullptr;
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
if (isPositiveAndBelow (indexToRemove, values.size()))
{
auto** e = data.elements + indexToRemove;
removedItem = *e;
removedItem = values[indexToRemove];
--numUsed;
const int numToShift = numUsed - indexToRemove;
values.removeElements (indexToRemove, 1);
if (numToShift > 0)
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
if ((numUsed << 1) < data.numAllocated)
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
@ -670,11 +592,10 @@ public:
void removeObject (const ObjectClass* objectToRemove, bool deleteObject = true)
{
const ScopedLockType lock (getLock());
auto** e = data.elements.get();
for (int i = 0; i < numUsed; ++i)
for (int i = 0; i < values.size(); ++i)
{
if (objectToRemove == e[i])
if (objectToRemove == values[i])
{
remove (i, deleteObject);
break;
@ -698,32 +619,24 @@ public:
void removeRange (int startIndex, int numberToRemove, bool deleteObjects = true)
{
const ScopedLockType lock (getLock());
auto endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
startIndex = jlimit (0, numUsed, startIndex);
auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
startIndex = jlimit (0, values.size(), startIndex);
numberToRemove = endIndex - startIndex;
if (endIndex > startIndex)
if (numberToRemove > 0)
{
if (deleteObjects)
{
for (int i = startIndex; i < endIndex; ++i)
{
ContainerDeletePolicy<ObjectClass>::destroy (data.elements[i]);
data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
ContainerDeletePolicy<ObjectClass>::destroy (values[i]);
values[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
}
}
auto rangeSize = endIndex - startIndex;
auto** e = data.elements + startIndex;
auto numToShift = numUsed - endIndex;
numUsed -= rangeSize;
values.removeElements (startIndex, numberToRemove);
while (--numToShift >= 0)
{
*e = e[rangeSize];
++e;
}
if ((numUsed << 1) < data.numAllocated)
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
}
@ -739,10 +652,10 @@ public:
{
const ScopedLockType lock (getLock());
if (howManyToRemove >= numUsed)
if (howManyToRemove >= values.size())
clear (deleteObjects);
else
removeRange (numUsed - howManyToRemove, howManyToRemove, deleteObjects);
removeRange (values.size() - howManyToRemove, howManyToRemove, deleteObjects);
}
/** Swaps a pair of objects in the array.
@ -750,17 +663,10 @@ public:
If either of the indexes passed in is out-of-range, nothing will happen,
otherwise the two objects at these positions will be exchanged.
*/
void swap (int index1,
int index2) noexcept
void swap (int index1, int index2) noexcept
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (index1, numUsed)
&& isPositiveAndBelow (index2, numUsed))
{
std::swap (data.elements[index1],
data.elements[index2]);
}
values.swap (index1, index2);
}
/** Moves one of the objects to a different position.
@ -781,29 +687,7 @@ public:
if (currentIndex != newIndex)
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (currentIndex, numUsed))
{
if (! isPositiveAndBelow (newIndex, numUsed))
newIndex = numUsed - 1;
auto* value = data.elements[currentIndex];
if (newIndex > currentIndex)
{
memmove (data.elements + currentIndex,
data.elements + currentIndex + 1,
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
}
else
{
memmove (data.elements + newIndex + 1,
data.elements + newIndex,
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
}
data.elements[newIndex] = value;
}
values.move (currentIndex, newIndex);
}
}
@ -817,8 +701,7 @@ public:
{
const ScopedLockType lock1 (getLock());
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
data.swapWith (otherArray.data);
std::swap (numUsed, otherArray.numUsed);
values.swapWith (otherArray.values);
}
//==============================================================================
@ -831,7 +714,7 @@ public:
void minimiseStorageOverheads() noexcept
{
const ScopedLockType lock (getLock());
data.shrinkToNoMoreThan (numUsed);
values.shrinkToNoMoreThan (values.size());
}
/** Increases the array's internal storage to hold a minimum number of elements.
@ -843,7 +726,7 @@ public:
void ensureStorageAllocated (const int minNumElements) noexcept
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (minNumElements);
values.ensureAllocatedSize (minNumElements);
}
//==============================================================================
@ -876,13 +759,14 @@ public:
void sort (ElementComparator& comparator,
bool retainOrderOfEquivalentItems = false) const noexcept
{
ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused (comparator);
const ScopedLockType lock (getLock());
if (size() > 1)
sortArray (comparator, data.elements.get(), 0, size() - 1, retainOrderOfEquivalentItems);
sortArray (comparator, values.begin(), 0, size() - 1, retainOrderOfEquivalentItems);
}
//==============================================================================
@ -890,12 +774,11 @@ 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 values; }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
//==============================================================================
#ifndef DOXYGEN
// Note that the swapWithArray method has been replaced by a more flexible templated version,
@ -905,15 +788,19 @@ public:
private:
//==============================================================================
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
int numUsed = 0;
ArrayBase <ObjectClass*, TypeOfCriticalSectionToUse> values;
void deleteAllObjects()
{
while (numUsed > 0)
ContainerDeletePolicy<ObjectClass>::destroy (data.elements[--numUsed]);
for (auto& e : values)
ContainerDeletePolicy<ObjectClass>::destroy (e);
values.clear();
}
template <class OtherObjectClass, class OtherCriticalSection>
friend class OwnedArray;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
};

View File

@ -0,0 +1,122 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2018 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#if JUCE_UNIT_TESTS
class ReferenceCountedArrayTests : public UnitTest
{
public:
ReferenceCountedArrayTests() : UnitTest ("ReferenceCountedArray", "Containers") {}
//==============================================================================
void runTest() override
{
beginTest ("Add derived objects");
{
ReferenceCountedArray<TestDerivedObj> derivedArray;
derivedArray.add (static_cast<TestDerivedObj*> (new TestBaseObj()));
expectEquals (derivedArray.size(), 1);
expectEquals (derivedArray.getObjectPointer (0)->getReferenceCount(), 1);
expectEquals (derivedArray[0]->getReferenceCount(), 2);
for (auto o : derivedArray)
expectEquals (o->getReferenceCount(), 1);
ReferenceCountedArray<TestBaseObj> baseArray;
baseArray.addArray (derivedArray);
for (auto o : baseArray)
expectEquals (o->getReferenceCount(), 2);
derivedArray.clearQuick();
baseArray.clearQuick();
auto* baseObject = new TestBaseObj();
TestBaseObj::Ptr baseObjectPtr = baseObject;
expectEquals (baseObject->getReferenceCount(), 1);
auto* derivedObject = new TestDerivedObj();
TestDerivedObj::Ptr derivedObjectPtr = derivedObject;
expectEquals (derivedObject->getReferenceCount(), 1);
baseArray.add (baseObject);
baseArray.add (derivedObject);
for (auto o : baseArray)
expectEquals (o->getReferenceCount(), 2);
expectEquals (baseObject->getReferenceCount(), 2);
expectEquals (derivedObject->getReferenceCount(), 2);
derivedArray.add (derivedObject);
for (auto o : derivedArray)
expectEquals (o->getReferenceCount(), 3);
derivedArray.clearQuick();
baseArray.clearQuick();
expectEquals (baseObject->getReferenceCount(), 1);
expectEquals (derivedObject->getReferenceCount(), 1);
baseArray.add (baseObjectPtr);
#if JUCE_STRICT_REFCOUNTEDPOINTER
baseArray.add (derivedObjectPtr);
#else
baseArray.add (derivedObjectPtr.get());
#endif
for (auto o : baseArray)
expectEquals (o->getReferenceCount(), 2);
derivedArray.add (derivedObjectPtr);
for (auto o : derivedArray)
expectEquals (o->getReferenceCount(), 3);
}
}
private:
struct TestBaseObj : public ReferenceCountedObject
{
using Ptr = ReferenceCountedObjectPtr<TestBaseObj>;
TestBaseObj() = default;
};
struct TestDerivedObj : public TestBaseObj
{
using Ptr = ReferenceCountedObjectPtr<TestDerivedObj>;
TestDerivedObj() = default;
};
};
static ReferenceCountedArrayTests referenceCountedArrayTests;
#endif
} // namespace juce

View File

@ -56,17 +56,13 @@ public:
/** Creates an empty array.
@see ReferenceCountedObject, Array, OwnedArray
*/
ReferenceCountedArray() noexcept
{
}
ReferenceCountedArray() = default;
/** Creates a copy of another array */
ReferenceCountedArray (const ReferenceCountedArray& other) noexcept
{
const ScopedLockType lock (other.getLock());
numUsed = other.numUsed;
data.setAllocatedSize (numUsed);
memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*));
values.addArray (other.begin(), other.size());
for (auto* o : *this)
if (o != nullptr)
@ -75,10 +71,8 @@ public:
/** Moves from another array */
ReferenceCountedArray (ReferenceCountedArray&& other) noexcept
: data (static_cast<ArrayAllocationBase<ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data)),
numUsed (other.numUsed)
: values (std::move (other.values))
{
other.numUsed = 0;
}
/** Creates a copy of another array */
@ -86,9 +80,7 @@ public:
ReferenceCountedArray (const ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
{
const typename ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock (other.getLock());
numUsed = other.size();
data.setAllocatedSize (numUsed);
memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*));
values.addArray (other.begin(), other.size());
for (auto* o : *this)
if (o != nullptr)
@ -121,9 +113,7 @@ public:
ReferenceCountedArray& operator= (ReferenceCountedArray&& other) noexcept
{
releaseAllObjects();
data = static_cast<ArrayAllocationBase<ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data);
numUsed = other.numUsed;
other.numUsed = 0;
values = std::move (other.values);
return *this;
}
@ -137,13 +127,13 @@ public:
//==============================================================================
/** Removes all objects from the array.
Any objects in the array that whose reference counts drop to zero will be deleted.
Any objects in the array whose reference counts drop to zero will be deleted.
*/
void clear()
{
const ScopedLockType lock (getLock());
releaseAllObjects();
data.setAllocatedSize (0);
clearQuick();
values.setAllocatedSize (0);
}
/** Removes all objects from the array without freeing the array's allocated storage.
@ -159,13 +149,13 @@ public:
/** Returns the current number of objects in the array. */
inline int size() const noexcept
{
return numUsed;
return values.size();
}
/** Returns true if the array is empty, false otherwise. */
inline bool isEmpty() const noexcept
{
return numUsed == 0;
return size() == 0;
}
/** Returns a pointer to the object at this index in the array.
@ -178,7 +168,7 @@ public:
*/
inline ObjectClassPtr operator[] (int index) const noexcept
{
return getObjectPointer (index);
return ObjectClassPtr (getObjectPointer (index));
}
/** Returns a pointer to the object at this index in the array, without checking
@ -189,7 +179,7 @@ public:
*/
inline ObjectClassPtr getUnchecked (int index) const noexcept
{
return getObjectPointerUnchecked (index);
return ObjectClassPtr (getObjectPointerUnchecked (index));
}
/** Returns a raw pointer to the object at this index in the array.
@ -203,24 +193,16 @@ public:
inline ObjectClass* getObjectPointer (int index) const noexcept
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (index, numUsed))
{
jassert (data.elements != nullptr);
return data.elements[index];
}
return {};
return values.getValueWithDefault (index);
}
/** Returns a raw pointer to the object at this index in the array, without checking
whether the index is in-range.
*/
inline ObjectClass* getObjectPointerUnchecked (const int index) const noexcept
inline ObjectClass* getObjectPointerUnchecked (int index) const noexcept
{
const ScopedLockType lock (getLock());
jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
return data.elements[index];
return values[index];
}
/** Returns a pointer to the first object in the array.
@ -231,14 +213,7 @@ public:
inline ObjectClassPtr getFirst() const noexcept
{
const ScopedLockType lock (getLock());
if (numUsed > 0)
{
jassert (data.elements != nullptr);
return data.elements[0];
}
return {};
return values.getFirst();
}
/** Returns a pointer to the last object in the array.
@ -249,14 +224,7 @@ public:
inline ObjectClassPtr getLast() const noexcept
{
const ScopedLockType lock (getLock());
if (numUsed > 0)
{
jassert (data.elements != nullptr);
return data.elements[numUsed - 1];
}
return {};
return values.getLast();
}
/** Returns a pointer to the actual array data.
@ -265,7 +233,7 @@ public:
*/
inline ObjectClass** getRawDataPointer() const noexcept
{
return data.elements;
return values.begin();
}
//==============================================================================
@ -274,7 +242,7 @@ public:
*/
inline ObjectClass** begin() const noexcept
{
return data.elements;
return values.begin();
}
/** Returns a pointer to the element which follows the last element in the array.
@ -282,7 +250,15 @@ public:
*/
inline ObjectClass** end() const noexcept
{
return data.elements + numUsed;
return values.end();
}
/** Returns a pointer to the first element in the array.
This method is provided for compatibility with the standard C++ containers.
*/
inline ObjectClass** data() const noexcept
{
return begin();
}
//==============================================================================
@ -294,13 +270,13 @@ public:
int indexOf (const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock (getLock());
auto** e = data.elements.get();
auto** endPointer = e + numUsed;
auto** e = values.begin();
auto** endPointer = values.end();
while (e != endPointer)
{
if (objectToLookFor == *e)
return static_cast<int> (e - data.elements.get());
return static_cast<int> (e - values.begin());
++e;
}
@ -308,6 +284,13 @@ public:
return -1;
}
/** Finds the index of the first occurrence of an object in the array.
@param objectToLookFor the object to look for
@returns the index at which the object was found, or -1 if it's not found
*/
int indexOf (const ObjectClassPtr& objectToLookFor) const noexcept { return indexOf (objectToLookFor.get()); }
/** Returns true if the array contains a specified object.
@param objectToLookFor the object to look for
@ -316,8 +299,8 @@ public:
bool contains (const ObjectClass* objectToLookFor) const noexcept
{
const ScopedLockType lock (getLock());
auto** e = data.elements.get();
auto** endPointer = e + numUsed;
auto** e = values.begin();
auto** endPointer = values.end();
while (e != endPointer)
{
@ -330,6 +313,13 @@ public:
return false;
}
/** Returns true if the array contains a specified object.
@param objectToLookFor the object to look for
@returns true if the object is in the array
*/
bool contains (const ObjectClassPtr& objectToLookFor) const noexcept { return contains (objectToLookFor.get()); }
/** Appends a new object to the end of the array.
This will increase the new object's reference count.
@ -337,12 +327,42 @@ public:
@param newObject the new object to add to the array
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
*/
ObjectClass* add (ObjectClass* newObject) noexcept
ObjectClass* add (ObjectClass* newObject)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
data.elements[numUsed++] = newObject;
values.add (newObject);
if (newObject != nullptr)
newObject->incReferenceCount();
return newObject;
}
/** Appends a new object to the end of the array.
This will increase the new object's reference count.
@param newObject the new object to add to the array
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
*/
ObjectClass* add (const ObjectClassPtr& newObject) { return add (newObject.get()); }
/** Inserts a new object into the array at the given index.
If the index is less than 0 or greater than the size of the array, the
element will be added to the end of the array.
Otherwise, it will be inserted into the array, moving all the later elements
along to make room.
This will increase the new object's reference count.
@param indexToInsertAt the index at which the new element should be inserted
@param newObject the new object to add to the array
@see add, addSorted, addIfNotAlreadyThere, set
*/
ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject)
{
values.insert (indexToInsertAt, newObject, 1);
if (newObject != nullptr)
newObject->incReferenceCount();
@ -363,32 +383,25 @@ public:
@param newObject the new object to add to the array
@see add, addSorted, addIfNotAlreadyThere, set
*/
ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject) noexcept
{
if (indexToInsertAt < 0)
return add (newObject);
ObjectClass* insert (int indexToInsertAt, const ObjectClassPtr& newObject) { return insert (indexToInsertAt, newObject.get()); }
/** Appends a new object at the end of the array as long as the array doesn't
already contain it.
If the array already contains a matching object, nothing will be done.
@param newObject the new object to add to the array
@returns true if the object has been added, false otherwise
*/
bool addIfNotAlreadyThere (ObjectClass* newObject)
{
const ScopedLockType lock (getLock());
if (indexToInsertAt > numUsed)
indexToInsertAt = numUsed;
if (contains (newObject))
return false;
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
auto** e = data.elements + indexToInsertAt;
auto numToMove = numUsed - indexToInsertAt;
if (numToMove > 0)
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
*e = newObject;
if (newObject != nullptr)
newObject->incReferenceCount();
++numUsed;
return newObject;
add (newObject);
return true;
}
/** Appends a new object at the end of the array as long as the array doesn't
@ -399,16 +412,7 @@ public:
@param newObject the new object to add to the array
@returns true if the object has been added, false otherwise
*/
bool addIfNotAlreadyThere (ObjectClass* newObject) noexcept
{
const ScopedLockType lock (getLock());
if (contains (newObject))
return false;
add (newObject);
return true;
}
bool addIfNotAlreadyThere (const ObjectClassPtr& newObject) { return addIfNotAlreadyThere (newObject.get()); }
/** Replaces an object in the array with a different one.
@ -431,16 +435,14 @@ public:
if (newObject != nullptr)
newObject->incReferenceCount();
if (indexToChange < numUsed)
if (indexToChange < values.size())
{
releaseObject (data.elements[indexToChange]);
data.elements[indexToChange] = newObject;
releaseObject (values[indexToChange]);
values[indexToChange] = newObject;
}
else
{
data.ensureAllocatedSize (numUsed + 1);
jassert (data.elements != nullptr);
data.elements[numUsed++] = newObject;
values.add (newObject);
}
}
}
@ -463,22 +465,11 @@ public:
{
const ScopedLockType lock2 (getLock());
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
auto numElementsAdded = values.addArray (arrayToAddFrom.values, startIndex, numElementsToAdd);
auto** e = values.end();
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
numElementsToAdd = arrayToAddFrom.size() - startIndex;
if (numElementsToAdd > 0)
{
data.ensureAllocatedSize (numUsed + numElementsToAdd);
while (--numElementsToAdd >= 0)
add (arrayToAddFrom.getUnchecked (startIndex++));
}
for (int i = 0; i < numElementsAdded; ++i)
(*(--e))->incReferenceCount();
}
}
@ -498,7 +489,7 @@ public:
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
{
const ScopedLockType lock (getLock());
auto index = findInsertIndexInSortedArray (comparator, data.elements.get(), newObject, 0, numUsed);
auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
insert (index, newObject);
return index;
}
@ -512,9 +503,9 @@ public:
void addOrReplaceSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
{
const ScopedLockType lock (getLock());
auto index = findInsertIndexInSortedArray (comparator, data.elements.get(), newObject, 0, numUsed);
auto index = findInsertIndexInSortedArray (comparator, values.begin(), newObject, 0, values.size());
if (index > 0 && comparator.compareElements (newObject, data.elements[index - 1]) == 0)
if (index > 0 && comparator.compareElements (newObject, values[index - 1]) == 0)
set (index - 1, newObject); // replace an existing object that matches
else
insert (index, newObject); // no match, so insert the new one
@ -538,11 +529,11 @@ public:
{
ignoreUnused (comparator);
const ScopedLockType lock (getLock());
int s = 0, e = numUsed;
int s = 0, e = values.size();
while (s < e)
{
if (comparator.compareElements (objectToLookFor, data.elements[s]) == 0)
if (comparator.compareElements (objectToLookFor, values[s]) == 0)
return s;
auto halfway = (s + e) / 2;
@ -550,7 +541,7 @@ public:
if (halfway == s)
break;
if (comparator.compareElements (objectToLookFor, data.elements[halfway]) >= 0)
if (comparator.compareElements (objectToLookFor, values[halfway]) >= 0)
s = halfway;
else
e = halfway;
@ -577,17 +568,13 @@ public:
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
if (isPositiveAndBelow (indexToRemove, values.size()))
{
auto** e = data.elements + indexToRemove;
auto** e = values.begin() + indexToRemove;
releaseObject (*e);
--numUsed;
auto numberToShift = numUsed - indexToRemove;
values.removeElements (indexToRemove, 1);
if (numberToShift > 0)
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
if ((numUsed << 1) < data.numAllocated)
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
}
@ -606,18 +593,14 @@ public:
ObjectClassPtr removedItem;
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (indexToRemove, numUsed))
if (isPositiveAndBelow (indexToRemove, values.size()))
{
auto** e = data.elements + indexToRemove;
auto** e = values.begin() + indexToRemove;
removedItem = *e;
releaseObject (*e);
--numUsed;
auto numberToShift = numUsed - indexToRemove;
values.removeElements (indexToRemove, 1);
if (numberToShift > 0)
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
if ((numUsed << 1) < data.numAllocated)
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
@ -638,6 +621,16 @@ public:
remove (indexOf (objectToRemove));
}
/** Removes the first occurrence of a specified object from the array.
If the item isn't found, no action is taken. If it is found, it is
removed and has its reference count decreased.
@param objectToRemove the object to try to remove
@see remove, removeRange
*/
void removeObject (const ObjectClassPtr& objectToRemove) { removeObject (objectToRemove.get()); }
/** Removes a range of objects from the array.
This will remove a set of objects, starting from the given index,
@ -657,30 +650,21 @@ public:
int numberToRemove)
{
const ScopedLockType lock (getLock());
startIndex = jlimit (0, values.size(), startIndex);
auto endIndex = jlimit (0, values.size(), startIndex + numberToRemove);
numberToRemove = endIndex - startIndex;
auto start = jlimit (0, numUsed, startIndex);
auto endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
if (endIndex > start)
if (numberToRemove > 0)
{
for (int i = start; i < endIndex; ++i)
for (int i = startIndex; i < endIndex; ++i)
{
releaseObject (data.elements[i]);
data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
releaseObject (values[i]);
values[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
}
auto rangeSize = endIndex - start;
auto** e = data.elements + start;
int i = numUsed - endIndex;
numUsed -= rangeSize;
values.removeElements (startIndex, numberToRemove);
while (--i >= 0)
{
*e = e[rangeSize];
++e;
}
if ((numUsed << 1) < data.numAllocated)
if ((values.size() << 1) < values.capacity())
minimiseStorageOverheads();
}
}
@ -697,11 +681,11 @@ public:
{
const ScopedLockType lock (getLock());
if (howManyToRemove > numUsed)
howManyToRemove = numUsed;
if (howManyToRemove > values.size())
howManyToRemove = values.size();
while (--howManyToRemove >= 0)
remove (numUsed - 1);
remove (values.size() - 1);
}
/** Swaps a pair of objects in the array.
@ -713,11 +697,10 @@ public:
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (index1, numUsed)
&& isPositiveAndBelow (index2, numUsed))
if (isPositiveAndBelow (index1, values.size())
&& isPositiveAndBelow (index2, values.size()))
{
std::swap (data.elements[index1],
data.elements[index2]);
std::swap (values[index1], values[index2]);
}
}
@ -739,29 +722,7 @@ public:
if (currentIndex != newIndex)
{
const ScopedLockType lock (getLock());
if (isPositiveAndBelow (currentIndex, numUsed))
{
if (! isPositiveAndBelow (newIndex, numUsed))
newIndex = numUsed - 1;
auto* value = data.elements[currentIndex];
if (newIndex > currentIndex)
{
memmove (data.elements + currentIndex,
data.elements + currentIndex + 1,
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
}
else
{
memmove (data.elements + newIndex + 1,
data.elements + newIndex,
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
}
data.elements[newIndex] = value;
}
values.move (currentIndex, newIndex);
}
}
@ -776,8 +737,7 @@ public:
{
const ScopedLockType lock1 (getLock());
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
data.swapWith (otherArray.data);
std::swap (numUsed, otherArray.numUsed);
values.swapWith (otherArray.values);
}
//==============================================================================
@ -789,15 +749,7 @@ public:
{
const ScopedLockType lock2 (other.getLock());
const ScopedLockType lock1 (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 values == other.values;
}
/** Compares this array to another one.
@ -840,11 +792,12 @@ public:
void sort (ElementComparator& comparator,
bool retainOrderOfEquivalentItems = false) const noexcept
{
ignoreUnused (comparator); // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
// If you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
ignoreUnused (comparator);
const ScopedLockType lock (getLock());
sortArray (comparator, data.elements.get(), 0, size() - 1, retainOrderOfEquivalentItems);
sortArray (comparator, values.begin(), 0, values.size() - 1, retainOrderOfEquivalentItems);
}
//==============================================================================
@ -857,7 +810,7 @@ public:
void minimiseStorageOverheads() noexcept
{
const ScopedLockType lock (getLock());
data.shrinkToNoMoreThan (numUsed);
values.shrinkToNoMoreThan (values.size());
}
/** Increases the array's internal storage to hold a minimum number of elements.
@ -869,7 +822,7 @@ public:
void ensureStorageAllocated (const int minNumElements)
{
const ScopedLockType lock (getLock());
data.ensureAllocatedSize (minNumElements);
values.ensureAllocatedSize (minNumElements);
}
//==============================================================================
@ -877,12 +830,11 @@ 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 values; }
/** Returns the type of scoped lock to use for locking this array */
using ScopedLockType = typename TypeOfCriticalSectionToUse::ScopedLockType;
//==============================================================================
#ifndef DOXYGEN
// Note that the swapWithArray method has been replaced by a more flexible templated version,
@ -892,15 +844,14 @@ public:
private:
//==============================================================================
ArrayAllocationBase<ObjectClass*, TypeOfCriticalSectionToUse> data;
int numUsed = 0;
ArrayBase<ObjectClass*, TypeOfCriticalSectionToUse> values;
void releaseAllObjects()
{
while (numUsed > 0)
releaseObject (data.elements[--numUsed]);
for (auto& v : values)
releaseObject (v);
jassert (numUsed == 0);
values.clear();
}
static void releaseObject (ObjectClass* o)

View File

@ -59,24 +59,24 @@ public:
//==============================================================================
/** Creates an empty set. */
// VS2013 doesn't allow defaulted noexcept constructors.
SortedSet() noexcept {}
SortedSet() = default;
/** Creates a copy of another set. */
SortedSet (const SortedSet&) = default;
/** Creates a copy of another set. */
// VS2013 doesn't allow defaulted noexcept constructors.
SortedSet (SortedSet&& other) noexcept : data (static_cast<decltype(data)&&> (other.data)) {}
SortedSet (SortedSet&& other) noexcept : data (std::move (other.data)) {}
/** Makes a copy of another set. */
SortedSet& operator= (const SortedSet&) = default;
/** Makes a copy of another set. */
// VS2013 doesn't allow defaulted noexcept constructors.
SortedSet& operator= (SortedSet&& other) noexcept { data = static_cast<decltype(data)&&> (other.data); return *this; }
SortedSet& operator= (SortedSet&& other) noexcept { data = std::move (other.data); return *this; }
/** Destructor. */
~SortedSet() noexcept {}
~SortedSet() = default;
//==============================================================================
/** Compares this set to another one.

View File

@ -41,13 +41,13 @@ class SparseSet
{
public:
//==============================================================================
SparseSet() noexcept {}
SparseSet() = default;
SparseSet (const SparseSet&) = default;
SparseSet& operator= (const SparseSet&) = default;
SparseSet (SparseSet&& other) noexcept : ranges (static_cast<Array<Range<Type>>&&> (other.ranges)) {}
SparseSet& operator= (SparseSet&& other) noexcept { ranges = static_cast<Array<Range<Type>>&&> (other.ranges); return *this; }
SparseSet (SparseSet&& other) noexcept : ranges (std::move (other.ranges)) {}
SparseSet& operator= (SparseSet&& other) noexcept { ranges = std::move (other.ranges); return *this; }
//==============================================================================
/** Clears the set. */

View File

@ -53,17 +53,18 @@ public:
virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; }
virtual var clone (const var& original) const { return original; }
virtual bool isVoid() const noexcept { return false; }
virtual bool isUndefined() const noexcept { return false; }
virtual bool isInt() const noexcept { return false; }
virtual bool isInt64() const noexcept { return false; }
virtual bool isBool() const noexcept { return false; }
virtual bool isDouble() const noexcept { return false; }
virtual bool isString() const noexcept { return false; }
virtual bool isObject() const noexcept { return false; }
virtual bool isArray() const noexcept { return false; }
virtual bool isBinary() const noexcept { return false; }
virtual bool isMethod() const noexcept { return false; }
virtual bool isVoid() const noexcept { return false; }
virtual bool isUndefined() const noexcept { return false; }
virtual bool isInt() const noexcept { return false; }
virtual bool isInt64() const noexcept { return false; }
virtual bool isBool() const noexcept { return false; }
virtual bool isDouble() const noexcept { return false; }
virtual bool isString() const noexcept { return false; }
virtual bool isObject() const noexcept { return false; }
virtual bool isArray() const noexcept { return false; }
virtual bool isBinary() const noexcept { return false; }
virtual bool isMethod() const noexcept { return false; }
virtual bool isComparable() const noexcept { return false; }
virtual void cleanUp (ValueUnion&) const noexcept {}
virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; }
@ -78,7 +79,8 @@ public:
VariantType_Void() noexcept {}
static const VariantType_Void instance;
bool isVoid() const noexcept override { return true; }
bool isVoid() const noexcept override { return true; }
bool isComparable() const noexcept override { return true; }
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); }
void writeToStream (const ValueUnion&, OutputStream& output) const override { output.writeCompressedInt (0); }
};
@ -114,6 +116,7 @@ public:
String toString (const ValueUnion& data) const override { return String (data.intValue); }
bool toBool (const ValueUnion& data) const noexcept override { return data.intValue != 0; }
bool isInt() const noexcept override { return true; }
bool isComparable() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
@ -144,6 +147,7 @@ public:
String toString (const ValueUnion& data) const override { return String (data.int64Value); }
bool toBool (const ValueUnion& data) const noexcept override { return data.int64Value != 0; }
bool isInt64() const noexcept override { return true; }
bool isComparable() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
@ -171,9 +175,10 @@ public:
int toInt (const ValueUnion& data) const noexcept override { return (int) data.doubleValue; }
int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.doubleValue; }
double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; }
String toString (const ValueUnion& data) const override { return String (data.doubleValue, 20); }
String toString (const ValueUnion& data) const override { return serialiseDouble (data.doubleValue); }
bool toBool (const ValueUnion& data) const noexcept override { return data.doubleValue != 0.0; }
bool isDouble() const noexcept override { return true; }
bool isComparable() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
@ -201,6 +206,7 @@ public:
String toString (const ValueUnion& data) const override { return String::charToString (data.boolValue ? (juce_wchar) '1' : (juce_wchar) '0'); }
bool toBool (const ValueUnion& data) const noexcept override { return data.boolValue; }
bool isBool() const noexcept override { return true; }
bool isComparable() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
@ -232,6 +238,7 @@ public:
bool toBool (const ValueUnion& data) const noexcept override { return getString (data)->getIntValue() != 0
|| getString (data)->trim().equalsIgnoreCase ("true")
|| getString (data)->trim().equalsIgnoreCase ("yes"); }
bool isComparable() const noexcept override { return true; }
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
{
@ -356,7 +363,7 @@ public:
struct RefCountedArray : public ReferenceCountedObject
{
RefCountedArray (const Array<var>& a) : array (a) { incReferenceCount(); }
RefCountedArray (Array<var>&& a) : array (static_cast<Array<var>&&> (a)) { incReferenceCount(); }
RefCountedArray (Array<var>&& a) : array (std::move (a)) { incReferenceCount(); }
Array<var> array;
};
};
@ -536,24 +543,24 @@ var& var::operator= (var&& other) noexcept
var::var (String&& v) : type (&VariantType_String::instance)
{
new (value.stringValue) String (static_cast<String&&> (v));
new (value.stringValue) String (std::move (v));
}
var::var (MemoryBlock&& v) : type (&VariantType_Binary::instance)
{
value.binaryValue = new MemoryBlock (static_cast<MemoryBlock&&> (v));
value.binaryValue = new MemoryBlock (std::move (v));
}
var::var (Array<var>&& v) : type (&VariantType_Array::instance)
{
value.objectValue = new VariantType_Array::RefCountedArray (static_cast<Array<var>&&> (v));
value.objectValue = new VariantType_Array::RefCountedArray (std::move (v));
}
var& var::operator= (String&& v)
{
type->cleanUp (value);
type = &VariantType_String::instance;
new (value.stringValue) String (static_cast<String&&> (v));
new (value.stringValue) String (std::move (v));
return *this;
}
@ -565,7 +572,7 @@ bool var::equals (const var& other) const noexcept
bool var::equalsWithSameType (const var& other) const noexcept
{
return type == other.type && equals (other);
return hasSameTypeAs (other) && equals (other);
}
bool var::hasSameTypeAs (const var& other) const noexcept
@ -573,12 +580,31 @@ bool var::hasSameTypeAs (const var& other) const noexcept
return type == other.type;
}
bool operator== (const var& v1, const var& v2) noexcept { return v1.equals (v2); }
bool operator!= (const var& v1, const var& v2) noexcept { return ! v1.equals (v2); }
bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; }
bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; }
bool canCompare (const var& v1, const var& v2)
{
return v1.type->isComparable() && v2.type->isComparable();
}
static int compare (const var& v1, const var& v2)
{
if (v1.isString() && v2.isString())
return v1.toString().compare (v2.toString());
auto diff = static_cast<double> (v1) - static_cast<double> (v2);
return diff == 0 ? 0 : (diff < 0 ? -1 : 1);
}
bool operator== (const var& v1, const var& v2) { return v1.equals (v2); }
bool operator!= (const var& v1, const var& v2) { return ! v1.equals (v2); }
bool operator< (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) < 0; }
bool operator> (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) > 0; }
bool operator<= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) <= 0; }
bool operator>= (const var& v1, const var& v2) { return canCompare (v1, v2) && compare (v1, v2) >= 0; }
bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
bool operator== (const var& v1, const char* v2) { return v1.toString() == v2; }
bool operator!= (const var& v1, const char* v2) { return v1.toString() != v2; }
//==============================================================================
var var::clone() const noexcept
@ -666,7 +692,7 @@ var var::call (const Identifier& method, const var& arg1, const var& arg2, const
//==============================================================================
int var::size() const
{
if (auto* array = getArray())
if (auto array = getArray())
return array->size();
return 0;
@ -674,7 +700,7 @@ int var::size() const
const var& var::operator[] (int arrayIndex) const
{
auto* array = getArray();
auto array = getArray();
// When using this method, the var must actually be an array, and the index
// must be in-range!
@ -685,7 +711,7 @@ const var& var::operator[] (int arrayIndex) const
var& var::operator[] (int arrayIndex)
{
auto* array = getArray();
auto array = getArray();
// When using this method, the var must actually be an array, and the index
// must be in-range!
@ -696,10 +722,11 @@ var& var::operator[] (int arrayIndex)
Array<var>* var::convertToArray()
{
if (auto* array = getArray())
if (auto array = getArray())
return array;
Array<var> tempVar;
if (! isVoid())
tempVar.add (*this);
@ -714,7 +741,7 @@ void var::append (const var& n)
void var::remove (const int index)
{
if (auto* const array = getArray())
if (auto array = getArray())
array->remove (index);
}
@ -730,7 +757,7 @@ void var::resize (const int numArrayElementsWanted)
int var::indexOf (const var& n) const
{
if (auto* const array = getArray())
if (auto array = getArray())
return array->indexOf (n);
return -1;
@ -755,6 +782,7 @@ var var::readFromStream (InputStream& input)
case varMarker_BoolTrue: return var (true);
case varMarker_BoolFalse: return var (false);
case varMarker_Double: return var (input.readDouble());
case varMarker_String:
{
MemoryOutputStream mo;

View File

@ -286,18 +286,18 @@ public:
private:
//==============================================================================
class VariantType; friend class VariantType;
class VariantType_Void; friend class VariantType_Void;
class VariantType_Undefined; friend class VariantType_Undefined;
class VariantType_Int; friend class VariantType_Int;
class VariantType_Int64; friend class VariantType_Int64;
class VariantType_Double; friend class VariantType_Double;
class VariantType_Bool; friend class VariantType_Bool;
class VariantType_String; friend class VariantType_String;
class VariantType_Object; friend class VariantType_Object;
class VariantType_Array; friend class VariantType_Array;
class VariantType_Binary; friend class VariantType_Binary;
class VariantType_Method; friend class VariantType_Method;
class VariantType;
class VariantType_Void;
class VariantType_Undefined;
class VariantType_Int;
class VariantType_Int64;
class VariantType_Double;
class VariantType_Bool;
class VariantType_String;
class VariantType_Object;
class VariantType_Array;
class VariantType_Binary;
class VariantType_Method;
union ValueUnion
{
@ -311,17 +311,32 @@ private:
NativeFunction* methodValue;
};
friend bool canCompare (const var&, const var&);
const VariantType* type;
ValueUnion value;
Array<var>* convertToArray();
var (const VariantType&) noexcept;
// This is needed to prevent the wrong constructor/operator being called
var (const ReferenceCountedObject*) = delete;
var& operator= (const ReferenceCountedObject*) = delete;
};
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator== (const var&, const var&) noexcept;
JUCE_API bool operator== (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator!= (const var&, const var&) noexcept;
JUCE_API bool operator!= (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator< (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator<= (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator> (const var&, const var&);
/** Compares the values of two var objects, using the var::equals() comparison. */
JUCE_API bool operator>= (const var&, const var&);
JUCE_API bool operator== (const var&, const String&);
JUCE_API bool operator!= (const var&, const String&);
JUCE_API bool operator== (const var&, const char*);