| @@ -198,7 +198,7 @@ public: | |||
| size (other.size), | |||
| allocatedBytes (other.allocatedBytes), | |||
| channels (other.channels), | |||
| allocatedData (static_cast<HeapBlock<char, true>&&> (other.allocatedData)), | |||
| allocatedData (static_cast<HeapBlock<char>&&> (other.allocatedData)), | |||
| isClear (other.isClear) | |||
| { | |||
| memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace)); | |||
| @@ -214,7 +214,7 @@ public: | |||
| size = other.size; | |||
| allocatedBytes = other.allocatedBytes; | |||
| channels = other.channels; | |||
| allocatedData = static_cast<HeapBlock<char, true>&&> (other.allocatedData); | |||
| allocatedData = static_cast<HeapBlock<char>&&> (other.allocatedData); | |||
| isClear = other.isClear; | |||
| memcpy (preallocatedChannelSpace, other.preallocatedChannelSpace, sizeof (preallocatedChannelSpace)); | |||
| other.numChannels = 0; | |||
| @@ -323,14 +323,14 @@ public: | |||
| 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, | |||
| bool keepExistingContent = false, | |||
| bool clearExtraSpace = false, | |||
| 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) | |||
| { | |||
| @@ -341,7 +341,7 @@ public: | |||
| if (keepExistingContent) | |||
| { | |||
| HeapBlock<char, true> newData; | |||
| HeapBlock<char> newData; | |||
| newData.allocate (newTotalBytes, clearExtraSpace || isClear); | |||
| const size_t numSamplesToCopy = (size_t) jmin (newNumSamples, size); | |||
| @@ -375,8 +375,8 @@ public: | |||
| } | |||
| else | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN (allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear), false); | |||
| allocatedBytes = newTotalBytes; | |||
| allocatedData.allocate (newTotalBytes, clearExtraSpace || isClear); | |||
| channels = reinterpret_cast<float**> (allocatedData.getData()); | |||
| } | |||
| @@ -392,6 +392,8 @@ public: | |||
| size = newNumSamples; | |||
| numChannels = newNumChannels; | |||
| } | |||
| return true; | |||
| } | |||
| /** 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 | |||
| size of the arrays passed in | |||
| */ | |||
| void setDataToReferTo (float** dataToReferTo, | |||
| bool setDataToReferTo (float** dataToReferTo, | |||
| const int newNumChannels, | |||
| 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) | |||
| { | |||
| @@ -428,8 +430,7 @@ public: | |||
| numChannels = newNumChannels; | |||
| 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. | |||
| @@ -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: | |||
| //============================================================================== | |||
| int numChannels, size; | |||
| size_t allocatedBytes; | |||
| float** channels; | |||
| HeapBlock<char, true> allocatedData; | |||
| HeapBlock<char> allocatedData; | |||
| float* preallocatedChannelSpace [32]; | |||
| bool isClear; | |||
| void allocateData() | |||
| bool allocateData() | |||
| { | |||
| 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()); | |||
| float* chan = (float*) (allocatedData + channelListSize); | |||
| @@ -1065,11 +976,12 @@ private: | |||
| channels [numChannels] = nullptr; | |||
| 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) | |||
| if (numChannels < (int) numElementsInArray (preallocatedChannelSpace)) | |||
| @@ -1078,20 +990,21 @@ private: | |||
| } | |||
| 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()); | |||
| } | |||
| for (int i = 0; i < numChannels; ++i) | |||
| { | |||
| // 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 [numChannels] = nullptr; | |||
| isClear = false; | |||
| return true; | |||
| } | |||
| }; | |||
| @@ -68,10 +68,10 @@ public: | |||
| /** Creates a copy of another array. | |||
| @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; | |||
| data.setAllocatedSize (other.numUsed); | |||
| for (int i = 0; i < numUsed; ++i) | |||
| new (data.elements + i) ElementType (other.data.elements[i]); | |||
| @@ -91,10 +91,12 @@ public: | |||
| @param values the array to copy from | |||
| */ | |||
| template <typename TypeToCreateFrom> | |||
| explicit Array (const TypeToCreateFrom* values) : numUsed (0) | |||
| explicit Array (const TypeToCreateFrom* values) noexcept : numUsed (0) | |||
| { | |||
| while (*values != TypeToCreateFrom()) | |||
| add (*values++); | |||
| { | |||
| CARLA_SAFE_ASSERT_BREAK(add (*values++)); | |||
| } | |||
| } | |||
| /** Initalises from a C array of values. | |||
| @@ -103,16 +105,16 @@ public: | |||
| @param numValues the number of values in the array | |||
| */ | |||
| 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) | |||
| new (data.elements + i) ElementType (values[i]); | |||
| } | |||
| /** Destructor. */ | |||
| ~Array() | |||
| ~Array() noexcept | |||
| { | |||
| deleteAllElements(); | |||
| } | |||
| @@ -120,7 +122,7 @@ public: | |||
| /** Copies another array. | |||
| @param other the array to copy | |||
| */ | |||
| Array& operator= (const Array& other) | |||
| Array& operator= (const Array& other) noexcept | |||
| { | |||
| if (this != &other) | |||
| { | |||
| @@ -180,7 +182,7 @@ public: | |||
| @see clearQuick | |||
| */ | |||
| void clear() | |||
| void clear() noexcept | |||
| { | |||
| deleteAllElements(); | |||
| data.setAllocatedSize (0); | |||
| @@ -190,7 +192,7 @@ public: | |||
| /** Removes all elements from the array without freeing the array's allocated storage. | |||
| @see clear | |||
| */ | |||
| void clearQuick() | |||
| void clearQuick() noexcept | |||
| { | |||
| deleteAllElements(); | |||
| numUsed = 0; | |||
| @@ -365,10 +367,13 @@ public: | |||
| @param newElement the new object to add to the array | |||
| @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); | |||
| return true; | |||
| } | |||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||
| @@ -377,10 +382,13 @@ public: | |||
| @param newElement the new object to add to the array | |||
| @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)); | |||
| return true; | |||
| } | |||
| #endif | |||
| @@ -396,10 +404,10 @@ public: | |||
| @param newElement the new object to add to the array | |||
| @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)) | |||
| { | |||
| @@ -407,7 +415,7 @@ public: | |||
| const int numberToMove = numUsed - indexToInsertAt; | |||
| 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); | |||
| ++numUsed; | |||
| @@ -416,6 +424,8 @@ public: | |||
| { | |||
| new (data.elements + numUsed++) ElementType (newElement); | |||
| } | |||
| return true; | |||
| } | |||
| /** Inserts multiple copies of an element into the array at a given position. | |||
| @@ -513,8 +523,7 @@ public: | |||
| if (contains (newElement)) | |||
| return false; | |||
| add (newElement); | |||
| return true; | |||
| return add (newElement); | |||
| } | |||
| /** Replaces an element with a new value. | |||
| @@ -1035,9 +1044,9 @@ public: | |||
| removing elements, they may have quite a lot of unused space allocated. | |||
| 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. | |||
| @@ -1046,9 +1055,9 @@ 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) | |||
| 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 | |||
| 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 | |||
| */ | |||
| template <class ElementType> | |||
| @@ -83,17 +80,24 @@ public: | |||
| @param numElements the number of elements that are needed | |||
| */ | |||
| void setAllocatedSize (const int numElements) | |||
| bool setAllocatedSize (const int numElements) noexcept | |||
| { | |||
| if (numAllocated != numElements) | |||
| { | |||
| if (numElements > 0) | |||
| elements.realloc ((size_t) numElements); | |||
| { | |||
| if (! elements.realloc ((size_t) numElements)) | |||
| return false; | |||
| } | |||
| else | |||
| { | |||
| elements.free(); | |||
| } | |||
| numAllocated = numElements; | |||
| } | |||
| return true; | |||
| } | |||
| /** 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 | |||
| */ | |||
| void ensureAllocatedSize (const int minNumElements) | |||
| bool ensureAllocatedSize (const int minNumElements) noexcept | |||
| { | |||
| 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 | |||
| the given number of elements. | |||
| */ | |||
| void shrinkToNoMoreThan (const int maxNumElements) | |||
| bool shrinkToNoMoreThan (const int maxNumElements) noexcept | |||
| { | |||
| if (maxNumElements < numAllocated) | |||
| setAllocatedSize (maxNumElements); | |||
| return setAllocatedSize (maxNumElements); | |||
| return true; | |||
| } | |||
| /** Swap the contents of two objects. */ | |||
| @@ -271,8 +271,9 @@ public: | |||
| */ | |||
| ObjectClass* add (ObjectClass* newObject) noexcept | |||
| { | |||
| data.ensureAllocatedSize (numUsed + 1); | |||
| jassert (data.elements != nullptr); | |||
| if (! data.ensureAllocatedSize (numUsed + 1)) | |||
| return nullptr; | |||
| data.elements [numUsed++] = newObject; | |||
| return newObject; | |||
| } | |||
| @@ -303,14 +304,14 @@ public: | |||
| if (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; | |||
| const int numToMove = numUsed - indexToInsertAt; | |||
| if (numToMove > 0) | |||
| memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove); | |||
| std::memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove); | |||
| *e = newObject; | |||
| ++numUsed; | |||
| @@ -369,8 +370,7 @@ public: | |||
| if (contains (newObject)) | |||
| return false; | |||
| add (newObject); | |||
| return true; | |||
| return add (newObject) != nullptr; | |||
| } | |||
| /** 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. | |||
| 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. | |||
| @@ -782,9 +782,9 @@ 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) 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 | |||
| 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 | |||
| */ | |||
| template <class ElementType, bool throwOnFailure = false> | |||
| template <class ElementType> | |||
| class HeapBlock | |||
| { | |||
| public: | |||
| @@ -181,7 +176,7 @@ public: | |||
| The data that is allocated will be freed when this object is deleted, or when you | |||
| 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); | |||
| data = static_cast<ElementType*> (std::malloc (newNumElements * elementSize)); | |||
| @@ -192,7 +187,7 @@ public: | |||
| /** 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. | |||
| */ | |||
| 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); | |||
| 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 | |||
| initialiseToZero parameter. | |||
| */ | |||
| bool allocate (const size_t newNumElements, bool initialiseToZero) | |||
| bool allocate (const size_t newNumElements, bool initialiseToZero) noexcept | |||
| { | |||
| std::free (data); | |||
| data = static_cast<ElementType*> (initialiseToZero | |||
| @@ -219,7 +214,7 @@ public: | |||
| 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. | |||
| */ | |||
| 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) | |||
| : std::realloc (data, newNumElements * elementSize)); | |||
| @@ -238,8 +233,7 @@ public: | |||
| /** Swaps this object's data with the data of another HeapBlock. | |||
| 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); | |||
| } | |||
| @@ -24,6 +24,7 @@ | |||
| */ | |||
| #include "Time.h" | |||
| #include "../memory/Atomic.h" | |||
| #include <ctime> | |||
| #include <sys/time.h> | |||
| @@ -38,7 +39,7 @@ namespace water { | |||
| namespace TimeHelpers | |||
| { | |||
| static uint32 lastMSCounterValue = 0; | |||
| static Atomic<uint32> lastMSCounterValue; | |||
| #ifdef CARLA_OS_MAC | |||
| /* 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(); | |||
| if (now < TimeHelpers::lastMSCounterValue) | |||
| if (now < TimeHelpers::lastMSCounterValue.get()) | |||
| { | |||
| // in multi-threaded apps this might be called concurrently, so | |||
| // make sure that our last counter value only increases and doesn't | |||
| // go backwards.. | |||
| if (now < TimeHelpers::lastMSCounterValue - 1000) | |||
| if (now < TimeHelpers::lastMSCounterValue.get() - 1000U) | |||
| TimeHelpers::lastMSCounterValue = now; | |||
| } | |||
| else | |||
| @@ -147,10 +148,8 @@ uint32 Time::getMillisecondCounter() noexcept | |||
| uint32 Time::getApproximateMillisecondCounter() noexcept | |||
| { | |||
| if (TimeHelpers::lastMSCounterValue == 0) | |||
| getMillisecondCounter(); | |||
| return TimeHelpers::lastMSCounterValue; | |||
| const uint32 t = TimeHelpers::lastMSCounterValue.get(); | |||
| return t == 0 ? getMillisecondCounter() : t; | |||
| } | |||
| } | |||