| @@ -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; | |||||
| } | } | ||||
| } | } | ||||