@@ -198,7 +198,7 @@ public: | |||||
size (other.size), | size (other.size), | ||||
allocatedBytes (other.allocatedBytes), | allocatedBytes (other.allocatedBytes), | ||||
channels (other.channels), | channels (other.channels), | ||||
allocatedData (static_cast<HeapBlock<char, true>&&> (other.allocatedData)), | |||||
allocatedData (static_cast<HeapBlock<char>&&> (other.allocatedData)), | |||||
isClear (other.isClear) | isClear (other.isClear) | ||||
{ | { | ||||
memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace)); | memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace)); | ||||
@@ -214,7 +214,7 @@ public: | |||||
size = other.size; | size = other.size; | ||||
allocatedBytes = other.allocatedBytes; | allocatedBytes = other.allocatedBytes; | ||||
channels = other.channels; | channels = other.channels; | ||||
allocatedData = static_cast<HeapBlock<char, true>&&> (other.allocatedData); | |||||
allocatedData = static_cast<HeapBlock<char>&&> (other.allocatedData); | |||||
isClear = other.isClear; | isClear = other.isClear; | ||||
memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace)); | memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace)); | ||||
other.numChannels = 0; | other.numChannels = 0; | ||||
@@ -323,14 +323,14 @@ public: | |||||
If the required memory can't be allocated, this will throw a std::bad_alloc exception. | If the required memory can't be allocated, this will throw a std::bad_alloc exception. | ||||
*/ | */ | ||||
void setSize (int newNumChannels, | |||||
bool setSize (int newNumChannels, | |||||
int newNumSamples, | int newNumSamples, | ||||
bool keepExistingContent = false, | bool keepExistingContent = false, | ||||
bool clearExtraSpace = false, | bool clearExtraSpace = false, | ||||
bool avoidReallocating = false) noexcept | bool avoidReallocating = false) noexcept | ||||
{ | { | ||||
jassert (newNumChannels >= 0); | |||||
jassert (newNumSamples >= 0); | |||||
CARLA_SAFE_ASSERT_RETURN (newNumChannels >= 0, false); | |||||
CARLA_SAFE_ASSERT_RETURN (newNumSamples >= 0, false); | |||||
if (newNumSamples != size || newNumChannels != numChannels) | if (newNumSamples != size || newNumChannels != numChannels) | ||||
{ | { | ||||
@@ -341,7 +341,7 @@ public: | |||||
if (keepExistingContent) | if (keepExistingContent) | ||||
{ | { | ||||
HeapBlock<char, true> newData; | |||||
HeapBlock<char> newData; | |||||
newData.allocate (newTotalBytes, clearExtraSpace || isClear); | newData.allocate (newTotalBytes, clearExtraSpace || isClear); | ||||
const size_t numSamplesToCopy = (size_t) jmin (newNumSamples, size); | const size_t numSamplesToCopy = (size_t) jmin (newNumSamples, size); | ||||
@@ -375,8 +375,8 @@ public: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN (allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear), false); | |||||
allocatedBytes = newTotalBytes; | allocatedBytes = newTotalBytes; | ||||
allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear); | |||||
channels = reinterpret_cast<float**> (allocatedData.getData()); | channels = reinterpret_cast<float**> (allocatedData.getData()); | ||||
} | } | ||||
@@ -392,6 +392,8 @@ public: | |||||
size = newNumSamples; | size = newNumSamples; | ||||
numChannels = newNumChannels; | numChannels = newNumChannels; | ||||
} | } | ||||
return true; | |||||
} | } | ||||
/** Makes this buffer point to a pre-allocated set of channel data arrays. | /** Makes this buffer point to a pre-allocated set of channel data arrays. | ||||
@@ -412,12 +414,12 @@ public: | |||||
@param newNumSamples the number of samples to use - this must correspond to the | @param newNumSamples the number of samples to use - this must correspond to the | ||||
size of the arrays passed in | size of the arrays passed in | ||||
*/ | */ | ||||
void setDataToReferTo (float** dataToReferTo, | |||||
bool setDataToReferTo (float** dataToReferTo, | |||||
const int newNumChannels, | const int newNumChannels, | ||||
const int newNumSamples) noexcept | const int newNumSamples) noexcept | ||||
{ | { | ||||
jassert (dataToReferTo != nullptr); | |||||
jassert (newNumChannels >= 0 && newNumSamples >= 0); | |||||
CARLA_SAFE_ASSERT_RETURN (dataToReferTo != nullptr, false); | |||||
CARLA_SAFE_ASSERT_RETURN (newNumChannels >= 0 && newNumSamples >= 0, false); | |||||
if (allocatedBytes != 0) | if (allocatedBytes != 0) | ||||
{ | { | ||||
@@ -428,8 +430,7 @@ public: | |||||
numChannels = newNumChannels; | numChannels = newNumChannels; | ||||
size = newNumSamples; | size = newNumSamples; | ||||
allocateChannels (dataToReferTo, 0); | |||||
jassert (! isClear); | |||||
return allocateChannels (dataToReferTo, 0); | |||||
} | } | ||||
/** Resizes this buffer to match the given one, and copies all of its content across. | /** Resizes this buffer to match the given one, and copies all of its content across. | ||||
@@ -948,112 +949,22 @@ public: | |||||
} | } | ||||
} | } | ||||
#if 0 | |||||
/** Returns a Range indicating the lowest and highest sample values in a given section. | |||||
@param channel the channel to read from | |||||
@param startSample the start sample within the channel | |||||
@param numSamples the number of samples to check | |||||
*/ | |||||
Range<float> findMinMax (int channel, | |||||
int startSample, | |||||
int numSamples) const noexcept | |||||
{ | |||||
jassert (isPositiveAndBelow (channel, numChannels)); | |||||
jassert (startSample >= 0 && startSample + numSamples <= size); | |||||
if (isClear) | |||||
return Range<float>(); | |||||
return FloatVectorOperations::findMinAndMax (channels [channel] + startSample, numSamples); | |||||
} | |||||
/** Finds the highest absolute sample value within a region of a channel. */ | |||||
float getMagnitude (int channel, | |||||
int startSample, | |||||
int numSamples) const noexcept | |||||
{ | |||||
jassert (isPositiveAndBelow (channel, numChannels)); | |||||
jassert (startSample >= 0 && startSample + numSamples <= size); | |||||
if (isClear) | |||||
return 0.0f; | |||||
const Range<float> r (findMinMax (channel, startSample, numSamples)); | |||||
return jmax (r.getStart(), -r.getStart(), r.getEnd(), -r.getEnd()); | |||||
} | |||||
/** Finds the highest absolute sample value within a region on all channels. */ | |||||
float getMagnitude (int startSample, | |||||
int numSamples) const noexcept | |||||
{ | |||||
float mag = 0.0f; | |||||
if (! isClear) | |||||
for (int i = 0; i < numChannels; ++i) | |||||
mag = jmax (mag, getMagnitude (i, startSample, numSamples)); | |||||
return mag; | |||||
} | |||||
/** Returns the root mean squared level for a region of a channel. */ | |||||
float getRMSLevel (int channel, | |||||
int startSample, | |||||
int numSamples) const noexcept | |||||
{ | |||||
jassert (isPositiveAndBelow (channel, numChannels)); | |||||
jassert (startSample >= 0 && startSample + numSamples <= size); | |||||
if (numSamples <= 0 || channel < 0 || channel >= numChannels || isClear) | |||||
return 0.0f; | |||||
const float* const data = channels [channel] + startSample; | |||||
double sum = 0.0; | |||||
for (int i = 0; i < numSamples; ++i) | |||||
{ | |||||
const float sample = data [i]; | |||||
sum += sample * sample; | |||||
} | |||||
return (float) std::sqrt (sum / numSamples); | |||||
} | |||||
/** Reverses a part of a channel. */ | |||||
void reverse (int channel, int startSample, int numSamples) const noexcept | |||||
{ | |||||
jassert (isPositiveAndBelow (channel, numChannels)); | |||||
jassert (startSample >= 0 && startSample + numSamples <= size); | |||||
if (! isClear) | |||||
std::reverse (channels[channel] + startSample, | |||||
channels[channel] + startSample + numSamples); | |||||
} | |||||
/** Reverses a part of the buffer. */ | |||||
void reverse (int startSample, int numSamples) const noexcept | |||||
{ | |||||
for (int i = 0; i < numChannels; ++i) | |||||
reverse (i, startSample, numSamples); | |||||
} | |||||
#endif | |||||
private: | private: | ||||
//============================================================================== | //============================================================================== | ||||
int numChannels, size; | int numChannels, size; | ||||
size_t allocatedBytes; | size_t allocatedBytes; | ||||
float** channels; | float** channels; | ||||
HeapBlock<char, true> allocatedData; | |||||
HeapBlock<char> allocatedData; | |||||
float* preallocatedChannelSpace [32]; | float* preallocatedChannelSpace [32]; | ||||
bool isClear; | bool isClear; | ||||
void allocateData() | |||||
bool allocateData() | |||||
{ | { | ||||
const size_t channelListSize = sizeof (float*) * (size_t) (numChannels + 1); | const size_t channelListSize = sizeof (float*) * (size_t) (numChannels + 1); | ||||
allocatedBytes = (size_t) numChannels * (size_t) size * sizeof (float) + channelListSize + 32; | |||||
allocatedData.malloc (allocatedBytes); | |||||
const size_t nextAllocatedBytes = (size_t) numChannels * (size_t) size * sizeof (float) + channelListSize + 32; | |||||
CARLA_SAFE_ASSERT_RETURN (allocatedData.malloc (nextAllocatedBytes), false); | |||||
allocatedBytes = nextAllocatedBytes; | |||||
channels = reinterpret_cast<float**> (allocatedData.getData()); | channels = reinterpret_cast<float**> (allocatedData.getData()); | ||||
float* chan = (float*) (allocatedData + channelListSize); | float* chan = (float*) (allocatedData + channelListSize); | ||||
@@ -1065,11 +976,12 @@ private: | |||||
channels [numChannels] = nullptr; | channels [numChannels] = nullptr; | ||||
isClear = false; | isClear = false; | ||||
return true; | |||||
} | } | ||||
void allocateChannels (float* const* const dataToReferTo, int offset) | |||||
bool allocateChannels (float* const* const dataToReferTo, int offset) | |||||
{ | { | ||||
jassert (offset >= 0); | |||||
CARLA_SAFE_ASSERT_RETURN (offset >= 0, false); | |||||
// (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) | // (try to avoid doing a malloc here, as that'll blow up things like Pro-Tools) | ||||
if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) | if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) | ||||
@@ -1078,20 +990,21 @@ private: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
allocatedData.malloc ((size_t) numChannels + 1, sizeof (float*)); | |||||
CARLA_SAFE_ASSERT_RETURN( allocatedData.malloc ((size_t) numChannels + 1, sizeof (float*)), false); | |||||
channels = reinterpret_cast<float**> (allocatedData.getData()); | channels = reinterpret_cast<float**> (allocatedData.getData()); | ||||
} | } | ||||
for (int i = 0; i < numChannels; ++i) | for (int i = 0; i < numChannels; ++i) | ||||
{ | { | ||||
// you have to pass in the same number of valid pointers as numChannels | // you have to pass in the same number of valid pointers as numChannels | ||||
jassert (dataToReferTo[i] != nullptr); | |||||
CARLA_SAFE_ASSERT_CONTINUE (dataToReferTo[i] != nullptr); | |||||
channels[i] = dataToReferTo[i] + offset; | channels[i] = dataToReferTo[i] + offset; | ||||
} | } | ||||
channels [numChannels] = nullptr; | channels [numChannels] = nullptr; | ||||
isClear = false; | isClear = false; | ||||
return true; | |||||
} | } | ||||
}; | }; | ||||
@@ -68,10 +68,10 @@ public: | |||||
/** Creates a copy of another array. | /** Creates a copy of another array. | ||||
@param other the array to copy | @param other the array to copy | ||||
*/ | */ | ||||
Array (const Array<ElementType>& other) | |||||
Array (const Array<ElementType>& other) noexcept | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(data.setAllocatedSize (other.numUsed),); | |||||
numUsed = other.numUsed; | numUsed = other.numUsed; | ||||
data.setAllocatedSize (other.numUsed); | |||||
for (int i = 0; i < numUsed; ++i) | for (int i = 0; i < numUsed; ++i) | ||||
new (data.elements + i) ElementType (other.data.elements[i]); | new (data.elements + i) ElementType (other.data.elements[i]); | ||||
@@ -91,10 +91,12 @@ public: | |||||
@param values the array to copy from | @param values the array to copy from | ||||
*/ | */ | ||||
template <typename TypeToCreateFrom> | template <typename TypeToCreateFrom> | ||||
explicit Array (const TypeToCreateFrom* values) : numUsed (0) | |||||
explicit Array (const TypeToCreateFrom* values) noexcept : numUsed (0) | |||||
{ | { | ||||
while (*values != TypeToCreateFrom()) | while (*values != TypeToCreateFrom()) | ||||
add (*values++); | |||||
{ | |||||
CARLA_SAFE_ASSERT_BREAK(add (*values++)); | |||||
} | |||||
} | } | ||||
/** Initalises from a C array of values. | /** Initalises from a C array of values. | ||||
@@ -103,16 +105,16 @@ public: | |||||
@param numValues the number of values in the array | @param numValues the number of values in the array | ||||
*/ | */ | ||||
template <typename TypeToCreateFrom> | template <typename TypeToCreateFrom> | ||||
Array (const TypeToCreateFrom* values, int numValues) : numUsed (numValues) | |||||
Array (const TypeToCreateFrom* values, int numValues) noexcept : numUsed (numValues) | |||||
{ | { | ||||
data.setAllocatedSize (numValues); | |||||
CARLA_SAFE_ASSERT_RETURN(data.setAllocatedSize (numValues),); | |||||
for (int i = 0; i < numValues; ++i) | for (int i = 0; i < numValues; ++i) | ||||
new (data.elements + i) ElementType (values[i]); | new (data.elements + i) ElementType (values[i]); | ||||
} | } | ||||
/** Destructor. */ | /** Destructor. */ | ||||
~Array() | |||||
~Array() noexcept | |||||
{ | { | ||||
deleteAllElements(); | deleteAllElements(); | ||||
} | } | ||||
@@ -120,7 +122,7 @@ public: | |||||
/** Copies another array. | /** Copies another array. | ||||
@param other the array to copy | @param other the array to copy | ||||
*/ | */ | ||||
Array& operator= (const Array& other) | |||||
Array& operator= (const Array& other) noexcept | |||||
{ | { | ||||
if (this != &other) | if (this != &other) | ||||
{ | { | ||||
@@ -180,7 +182,7 @@ public: | |||||
@see clearQuick | @see clearQuick | ||||
*/ | */ | ||||
void clear() | |||||
void clear() noexcept | |||||
{ | { | ||||
deleteAllElements(); | deleteAllElements(); | ||||
data.setAllocatedSize (0); | data.setAllocatedSize (0); | ||||
@@ -190,7 +192,7 @@ public: | |||||
/** Removes all elements from the array without freeing the array's allocated storage. | /** Removes all elements from the array without freeing the array's allocated storage. | ||||
@see clear | @see clear | ||||
*/ | */ | ||||
void clearQuick() | |||||
void clearQuick() noexcept | |||||
{ | { | ||||
deleteAllElements(); | deleteAllElements(); | ||||
numUsed = 0; | numUsed = 0; | ||||
@@ -365,10 +367,13 @@ public: | |||||
@param newElement the new object to add to the array | @param newElement the new object to add to the array | ||||
@see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray | @see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray | ||||
*/ | */ | ||||
void add (const ElementType& newElement) | |||||
bool add (const ElementType& newElement) noexcept | |||||
{ | { | ||||
data.ensureAllocatedSize (numUsed + 1); | |||||
if (! data.ensureAllocatedSize (numUsed + 1)) | |||||
return false; | |||||
new (data.elements + numUsed++) ElementType (newElement); | new (data.elements + numUsed++) ElementType (newElement); | ||||
return true; | |||||
} | } | ||||
#if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | ||||
@@ -377,10 +382,13 @@ public: | |||||
@param newElement the new object to add to the array | @param newElement the new object to add to the array | ||||
@see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray | @see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray | ||||
*/ | */ | ||||
void add (ElementType&& newElement) | |||||
bool add (ElementType&& newElement) noexcept | |||||
{ | { | ||||
data.ensureAllocatedSize (numUsed + 1); | |||||
if (! data.ensureAllocatedSize (numUsed + 1)) | |||||
return false; | |||||
new (data.elements + numUsed++) ElementType (static_cast<ElementType&&> (newElement)); | new (data.elements + numUsed++) ElementType (static_cast<ElementType&&> (newElement)); | ||||
return true; | |||||
} | } | ||||
#endif | #endif | ||||
@@ -396,10 +404,10 @@ public: | |||||
@param newElement the new object to add to the array | @param newElement the new object to add to the array | ||||
@see add, addSorted, addUsingDefaultSort, set | @see add, addSorted, addUsingDefaultSort, set | ||||
*/ | */ | ||||
void insert (int indexToInsertAt, ParameterType newElement) | |||||
bool insert (int indexToInsertAt, ParameterType newElement) noexcept | |||||
{ | { | ||||
data.ensureAllocatedSize (numUsed + 1); | |||||
jassert (data.elements != nullptr); | |||||
if (! data.ensureAllocatedSize (numUsed + 1)) | |||||
return false; | |||||
if (isPositiveAndBelow (indexToInsertAt, numUsed)) | if (isPositiveAndBelow (indexToInsertAt, numUsed)) | ||||
{ | { | ||||
@@ -407,7 +415,7 @@ public: | |||||
const int numberToMove = numUsed - indexToInsertAt; | const int numberToMove = numUsed - indexToInsertAt; | ||||
if (numberToMove > 0) | if (numberToMove > 0) | ||||
memmove (insertPos + 1, insertPos, ((size_t) numberToMove) * sizeof (ElementType)); | |||||
std::memmove (insertPos + 1, insertPos, ((size_t) numberToMove) * sizeof (ElementType)); | |||||
new (insertPos) ElementType (newElement); | new (insertPos) ElementType (newElement); | ||||
++numUsed; | ++numUsed; | ||||
@@ -416,6 +424,8 @@ public: | |||||
{ | { | ||||
new (data.elements + numUsed++) ElementType (newElement); | new (data.elements + numUsed++) ElementType (newElement); | ||||
} | } | ||||
return true; | |||||
} | } | ||||
/** Inserts multiple copies of an element into the array at a given position. | /** Inserts multiple copies of an element into the array at a given position. | ||||
@@ -513,8 +523,7 @@ public: | |||||
if (contains (newElement)) | if (contains (newElement)) | ||||
return false; | return false; | ||||
add (newElement); | |||||
return true; | |||||
return add (newElement); | |||||
} | } | ||||
/** Replaces an element with a new value. | /** Replaces an element with a new value. | ||||
@@ -1035,9 +1044,9 @@ public: | |||||
removing elements, they may have quite a lot of unused space allocated. | removing elements, they may have quite a lot of unused space allocated. | ||||
This method will reduce the amount of allocated storage to a minimum. | This method will reduce the amount of allocated storage to a minimum. | ||||
*/ | */ | ||||
void minimiseStorageOverheads() | |||||
bool minimiseStorageOverheads() noexcept | |||||
{ | { | ||||
data.shrinkToNoMoreThan (numUsed); | |||||
return data.shrinkToNoMoreThan (numUsed); | |||||
} | } | ||||
/** Increases the array's internal storage to hold a minimum number of elements. | /** Increases the array's internal storage to hold a minimum number of elements. | ||||
@@ -1046,9 +1055,9 @@ public: | |||||
the array won't have to keep dynamically resizing itself as the elements | the array won't have to keep dynamically resizing itself as the elements | ||||
are added, and it'll therefore be more efficient. | are added, and it'll therefore be more efficient. | ||||
*/ | */ | ||||
void ensureStorageAllocated (const int minNumElements) | |||||
bool ensureStorageAllocated (const int minNumElements) noexcept | |||||
{ | { | ||||
data.ensureAllocatedSize (minNumElements); | |||||
return data.ensureAllocatedSize (minNumElements); | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
@@ -39,9 +39,6 @@ namespace water { | |||||
This class isn't really for public use - it's used by the other | This class isn't really for public use - it's used by the other | ||||
array classes, but might come in handy for some purposes. | 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 | @see Array, OwnedArray, ReferenceCountedArray | ||||
*/ | */ | ||||
template <class ElementType> | template <class ElementType> | ||||
@@ -83,17 +80,24 @@ public: | |||||
@param numElements the number of elements that are needed | @param numElements the number of elements that are needed | ||||
*/ | */ | ||||
void setAllocatedSize (const int numElements) | |||||
bool setAllocatedSize (const int numElements) noexcept | |||||
{ | { | ||||
if (numAllocated != numElements) | if (numAllocated != numElements) | ||||
{ | { | ||||
if (numElements > 0) | if (numElements > 0) | ||||
elements.realloc ((size_t) numElements); | |||||
{ | |||||
if (! elements.realloc ((size_t) numElements)) | |||||
return false; | |||||
} | |||||
else | else | ||||
{ | |||||
elements.free(); | elements.free(); | ||||
} | |||||
numAllocated = numElements; | numAllocated = numElements; | ||||
} | } | ||||
return true; | |||||
} | } | ||||
/** Increases the amount of storage allocated if it is less than a given amount. | /** Increases the amount of storage allocated if it is less than a given amount. | ||||
@@ -104,21 +108,23 @@ public: | |||||
@param minNumElements the minimum number of elements that are needed | @param minNumElements the minimum number of elements that are needed | ||||
*/ | */ | ||||
void ensureAllocatedSize (const int minNumElements) | |||||
bool ensureAllocatedSize (const int minNumElements) noexcept | |||||
{ | { | ||||
if (minNumElements > numAllocated) | if (minNumElements > numAllocated) | ||||
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7); | |||||
return setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7); | |||||
jassert (numAllocated <= 0 || elements != nullptr); | |||||
return true; | |||||
} | } | ||||
/** Minimises the amount of storage allocated so that it's no more than | /** Minimises the amount of storage allocated so that it's no more than | ||||
the given number of elements. | the given number of elements. | ||||
*/ | */ | ||||
void shrinkToNoMoreThan (const int maxNumElements) | |||||
bool shrinkToNoMoreThan (const int maxNumElements) noexcept | |||||
{ | { | ||||
if (maxNumElements < numAllocated) | if (maxNumElements < numAllocated) | ||||
setAllocatedSize (maxNumElements); | |||||
return setAllocatedSize (maxNumElements); | |||||
return true; | |||||
} | } | ||||
/** Swap the contents of two objects. */ | /** Swap the contents of two objects. */ | ||||
@@ -271,8 +271,9 @@ public: | |||||
*/ | */ | ||||
ObjectClass* add (ObjectClass* newObject) noexcept | ObjectClass* add (ObjectClass* newObject) noexcept | ||||
{ | { | ||||
data.ensureAllocatedSize (numUsed + 1); | |||||
jassert (data.elements != nullptr); | |||||
if (! data.ensureAllocatedSize (numUsed + 1)) | |||||
return nullptr; | |||||
data.elements [numUsed++] = newObject; | data.elements [numUsed++] = newObject; | ||||
return newObject; | return newObject; | ||||
} | } | ||||
@@ -303,14 +304,14 @@ public: | |||||
if (indexToInsertAt > numUsed) | if (indexToInsertAt > numUsed) | ||||
indexToInsertAt = numUsed; | indexToInsertAt = numUsed; | ||||
data.ensureAllocatedSize (numUsed + 1); | |||||
jassert (data.elements != nullptr); | |||||
if (! data.ensureAllocatedSize (numUsed + 1)) | |||||
return nullptr; | |||||
ObjectClass** const e = data.elements + indexToInsertAt; | ObjectClass** const e = data.elements + indexToInsertAt; | ||||
const int numToMove = numUsed - indexToInsertAt; | const int numToMove = numUsed - indexToInsertAt; | ||||
if (numToMove > 0) | if (numToMove > 0) | ||||
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove); | |||||
std::memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove); | |||||
*e = newObject; | *e = newObject; | ||||
++numUsed; | ++numUsed; | ||||
@@ -369,8 +370,7 @@ public: | |||||
if (contains (newObject)) | if (contains (newObject)) | ||||
return false; | return false; | ||||
add (newObject); | |||||
return true; | |||||
return add (newObject) != nullptr; | |||||
} | } | ||||
/** Replaces an object in the array with a different one. | /** Replaces an object in the array with a different one. | ||||
@@ -771,9 +771,9 @@ public: | |||||
removing elements, they may have quite a lot of unused space allocated. | removing elements, they may have quite a lot of unused space allocated. | ||||
This method will reduce the amount of allocated storage to a minimum. | This method will reduce the amount of allocated storage to a minimum. | ||||
*/ | */ | ||||
void minimiseStorageOverheads() noexcept | |||||
bool minimiseStorageOverheads() noexcept | |||||
{ | { | ||||
data.shrinkToNoMoreThan (numUsed); | |||||
return data.shrinkToNoMoreThan (numUsed); | |||||
} | } | ||||
/** Increases the array's internal storage to hold a minimum number of elements. | /** Increases the array's internal storage to hold a minimum number of elements. | ||||
@@ -782,9 +782,9 @@ public: | |||||
the array won't have to keep dynamically resizing itself as the elements | the array won't have to keep dynamically resizing itself as the elements | ||||
are added, and it'll therefore be more efficient. | are added, and it'll therefore be more efficient. | ||||
*/ | */ | ||||
void ensureStorageAllocated (const int minNumElements) noexcept | |||||
bool ensureStorageAllocated (const int minNumElements) noexcept | |||||
{ | { | ||||
data.ensureAllocatedSize (minNumElements); | |||||
return data.ensureAllocatedSize (minNumElements); | |||||
} | } | ||||
//============================================================================== | //============================================================================== | ||||
@@ -70,14 +70,9 @@ namespace water { | |||||
as their less object-oriented counterparts. Despite adding safety, you probably | as their less object-oriented counterparts. Despite adding safety, you probably | ||||
won't sacrifice any performance by using this in place of normal pointers. | won't sacrifice any performance by using this in place of normal pointers. | ||||
The throwOnFailure template parameter can be set to true if you'd like the class | |||||
to throw a std::bad_alloc exception when an allocation fails. If this is false, | |||||
then a failed allocation will just leave the heapblock with a null pointer (assuming | |||||
that the system's malloc() function doesn't throw). | |||||
@see Array, OwnedArray, MemoryBlock | @see Array, OwnedArray, MemoryBlock | ||||
*/ | */ | ||||
template <class ElementType, bool throwOnFailure = false> | |||||
template <class ElementType> | |||||
class HeapBlock | class HeapBlock | ||||
{ | { | ||||
public: | public: | ||||
@@ -181,7 +176,7 @@ public: | |||||
The data that is allocated will be freed when this object is deleted, or when you | The data that is allocated will be freed when this object is deleted, or when you | ||||
call free() or any of the allocation methods. | call free() or any of the allocation methods. | ||||
*/ | */ | ||||
bool malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) | |||||
bool malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) noexcept | |||||
{ | { | ||||
std::free (data); | std::free (data); | ||||
data = static_cast<ElementType*> (std::malloc (newNumElements * elementSize)); | data = static_cast<ElementType*> (std::malloc (newNumElements * elementSize)); | ||||
@@ -192,7 +187,7 @@ public: | |||||
/** Allocates a specified amount of memory and clears it. | /** Allocates a specified amount of memory and clears it. | ||||
This does the same job as the malloc() method, but clears the memory that it allocates. | This does the same job as the malloc() method, but clears the memory that it allocates. | ||||
*/ | */ | ||||
bool calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) | |||||
bool calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) noexcept | |||||
{ | { | ||||
std::free (data); | std::free (data); | ||||
data = static_cast<ElementType*> (std::calloc (newNumElements, elementSize)); | data = static_cast<ElementType*> (std::calloc (newNumElements, elementSize)); | ||||
@@ -204,7 +199,7 @@ public: | |||||
This does the same job as either malloc() or calloc(), depending on the | This does the same job as either malloc() or calloc(), depending on the | ||||
initialiseToZero parameter. | initialiseToZero parameter. | ||||
*/ | */ | ||||
bool allocate (const size_t newNumElements, bool initialiseToZero) | |||||
bool allocate (const size_t newNumElements, bool initialiseToZero) noexcept | |||||
{ | { | ||||
std::free (data); | std::free (data); | ||||
data = static_cast<ElementType*> (initialiseToZero | data = static_cast<ElementType*> (initialiseToZero | ||||
@@ -219,7 +214,7 @@ public: | |||||
The semantics of this method are the same as malloc() and calloc(), but it | The semantics of this method are the same as malloc() and calloc(), but it | ||||
uses realloc() to keep as much of the existing data as possible. | uses realloc() to keep as much of the existing data as possible. | ||||
*/ | */ | ||||
bool realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) | |||||
bool realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) noexcept | |||||
{ | { | ||||
data = static_cast<ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize) | data = static_cast<ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize) | ||||
: std::realloc (data, newNumElements * elementSize)); | : std::realloc (data, newNumElements * elementSize)); | ||||
@@ -238,8 +233,7 @@ public: | |||||
/** Swaps this object's data with the data of another HeapBlock. | /** Swaps this object's data with the data of another HeapBlock. | ||||
The two objects simply exchange their data pointers. | The two objects simply exchange their data pointers. | ||||
*/ | */ | ||||
template <bool otherBlockThrows> | |||||
void swapWith (HeapBlock<ElementType, otherBlockThrows>& other) noexcept | |||||
void swapWith (HeapBlock<ElementType>& other) noexcept | |||||
{ | { | ||||
std::swap (data, other.data); | std::swap (data, other.data); | ||||
} | } | ||||
@@ -24,6 +24,7 @@ | |||||
*/ | */ | ||||
#include "Time.h" | #include "Time.h" | ||||
#include "../memory/Atomic.h" | |||||
#include <ctime> | #include <ctime> | ||||
#include <sys/time.h> | #include <sys/time.h> | ||||
@@ -38,7 +39,7 @@ namespace water { | |||||
namespace TimeHelpers | namespace TimeHelpers | ||||
{ | { | ||||
static uint32 lastMSCounterValue = 0; | |||||
static Atomic<uint32> lastMSCounterValue; | |||||
#ifdef CARLA_OS_MAC | #ifdef CARLA_OS_MAC | ||||
/* NB: these are kept outside the HiResCounterInfo struct and initialised to 1 to avoid | /* NB: these are kept outside the HiResCounterInfo struct and initialised to 1 to avoid | ||||
@@ -129,12 +130,12 @@ uint32 Time::getMillisecondCounter() noexcept | |||||
{ | { | ||||
const uint32 now = water_millisecondsSinceStartup(); | const uint32 now = water_millisecondsSinceStartup(); | ||||
if (now < TimeHelpers::lastMSCounterValue) | |||||
if (now < TimeHelpers::lastMSCounterValue.get()) | |||||
{ | { | ||||
// in multi-threaded apps this might be called concurrently, so | // in multi-threaded apps this might be called concurrently, so | ||||
// make sure that our last counter value only increases and doesn't | // make sure that our last counter value only increases and doesn't | ||||
// go backwards.. | // go backwards.. | ||||
if (now < TimeHelpers::lastMSCounterValue - 1000) | |||||
if (now < TimeHelpers::lastMSCounterValue.get() - 1000U) | |||||
TimeHelpers::lastMSCounterValue = now; | TimeHelpers::lastMSCounterValue = now; | ||||
} | } | ||||
else | else | ||||
@@ -147,10 +148,8 @@ uint32 Time::getMillisecondCounter() noexcept | |||||
uint32 Time::getApproximateMillisecondCounter() noexcept | uint32 Time::getApproximateMillisecondCounter() noexcept | ||||
{ | { | ||||
if (TimeHelpers::lastMSCounterValue == 0) | |||||
getMillisecondCounter(); | |||||
return TimeHelpers::lastMSCounterValue; | |||||
const uint32 t = TimeHelpers::lastMSCounterValue.get(); | |||||
return t == 0 ? getMillisecondCounter() : t; | |||||
} | } | ||||
} | } |