| @@ -129,6 +129,7 @@ $(OBJDIR)/$(MODULENAME).mm.%64.o: $(MODULENAME).cpp | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| -include $(OBJS:%.o=%.d) | -include $(OBJS:%.o=%.d) | ||||
| -include $(OBJS_files:%.o=%.d) | |||||
| -include $(OBJS_posix32:%.o=%.d) | -include $(OBJS_posix32:%.o=%.d) | ||||
| -include $(OBJS_posix64:%.o=%.d) | -include $(OBJS_posix64:%.o=%.d) | ||||
| -include $(OBJS_win32:%.o=%.d) | -include $(OBJS_win32:%.o=%.d) | ||||
| @@ -3,7 +3,7 @@ | |||||
| This file is part of the Water library. | This file is part of the Water library. | ||||
| Copyright (c) 2016 ROLI Ltd. | Copyright (c) 2016 ROLI Ltd. | ||||
| Copyright (C) 2017 Filipe Coelho <falktx@falktx.com> | |||||
| Copyright (C) 2017-2018 Filipe Coelho <falktx@falktx.com> | |||||
| Permission is granted to use this software under the terms of the ISC license | Permission is granted to use this software under the terms of the ISC license | ||||
| http://www.isc.org/downloads/software-support-policy/isc-license/ | http://www.isc.org/downloads/software-support-policy/isc-license/ | ||||
| @@ -416,7 +416,7 @@ public: | |||||
| const int numberToMove = numUsed - indexToInsertAt; | const int numberToMove = numUsed - indexToInsertAt; | ||||
| if (numberToMove > 0) | if (numberToMove > 0) | ||||
| std::memmove (insertPos + 1, insertPos, ((size_t) numberToMove) * sizeof (ElementType)); | |||||
| data.moveMemory (insertPos + 1, insertPos, numberToMove); | |||||
| new (insertPos) ElementType (newElement); | new (insertPos) ElementType (newElement); | ||||
| ++numUsed; | ++numUsed; | ||||
| @@ -441,19 +441,21 @@ public: | |||||
| @param numberOfTimesToInsertIt how many copies of the value to insert | @param numberOfTimesToInsertIt how many copies of the value to insert | ||||
| @see insert, add, addSorted, set | @see insert, add, addSorted, set | ||||
| */ | */ | ||||
| void insertMultiple (int indexToInsertAt, ParameterType newElement, | |||||
| bool insertMultiple (int indexToInsertAt, ParameterType newElement, | |||||
| int numberOfTimesToInsertIt) | int numberOfTimesToInsertIt) | ||||
| { | { | ||||
| if (numberOfTimesToInsertIt > 0) | if (numberOfTimesToInsertIt > 0) | ||||
| { | { | ||||
| data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt); | |||||
| if (! data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt)) | |||||
| return false; | |||||
| ElementType* insertPos; | ElementType* insertPos; | ||||
| if (isPositiveAndBelow (indexToInsertAt, numUsed)) | if (isPositiveAndBelow (indexToInsertAt, numUsed)) | ||||
| { | { | ||||
| insertPos = data.elements + indexToInsertAt; | insertPos = data.elements + indexToInsertAt; | ||||
| const int numberToMove = numUsed - indexToInsertAt; | const int numberToMove = numUsed - indexToInsertAt; | ||||
| memmove (insertPos + numberOfTimesToInsertIt, insertPos, ((size_t) numberToMove) * sizeof (ElementType)); | |||||
| data.moveMemory (insertPos + numberOfTimesToInsertIt, insertPos, numberToMove); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -469,8 +471,11 @@ public: | |||||
| // new statement to avoid a compiler bug in VS2014 | // new statement to avoid a compiler bug in VS2014 | ||||
| } | } | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| #if 0 | |||||
| /** Inserts an array of values into this array at a given position. | /** Inserts an array of values into this array at a given position. | ||||
| If the index is less than 0 or greater than the size of the array, the | If the index is less than 0 or greater than the size of the array, the | ||||
| @@ -483,20 +488,22 @@ public: | |||||
| @param numberOfElements how many items are in the array | @param numberOfElements how many items are in the array | ||||
| @see insert, add, addSorted, set | @see insert, add, addSorted, set | ||||
| */ | */ | ||||
| void insertArray (int indexToInsertAt, | |||||
| bool insertArray (int indexToInsertAt, | |||||
| const ElementType* newElements, | const ElementType* newElements, | ||||
| int numberOfElements) | int numberOfElements) | ||||
| { | { | ||||
| if (numberOfElements > 0) | if (numberOfElements > 0) | ||||
| { | { | ||||
| data.ensureAllocatedSize (numUsed + numberOfElements); | |||||
| if (! data.ensureAllocatedSize (numUsed + numberOfElements)) | |||||
| return false; | |||||
| ElementType* insertPos = data.elements; | ElementType* insertPos = data.elements; | ||||
| if (isPositiveAndBelow (indexToInsertAt, numUsed)) | if (isPositiveAndBelow (indexToInsertAt, numUsed)) | ||||
| { | { | ||||
| insertPos += indexToInsertAt; | insertPos += indexToInsertAt; | ||||
| const int numberToMove = numUsed - indexToInsertAt; | const int numberToMove = numUsed - indexToInsertAt; | ||||
| memmove (insertPos + numberOfElements, insertPos, (size_t) numberToMove * sizeof (ElementType)); | |||||
| std::memmove (insertPos + numberOfElements, insertPos, (size_t) numberToMove * sizeof (ElementType)); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -508,7 +515,10 @@ public: | |||||
| while (--numberOfElements >= 0) | while (--numberOfElements >= 0) | ||||
| new (insertPos++) ElementType (*newElements++); | new (insertPos++) ElementType (*newElements++); | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| #endif | |||||
| /** Appends a new element at the end of the array as long as the array doesn't | /** Appends a new element at the end of the array as long as the array doesn't | ||||
| already contain it. | already contain it. | ||||
| @@ -903,7 +913,7 @@ public: | |||||
| const int numToShift = numUsed - endIndex; | const int numToShift = numUsed - endIndex; | ||||
| if (numToShift > 0) | if (numToShift > 0) | ||||
| memmove (e, e + numberToRemove, ((size_t) numToShift) * sizeof (ElementType)); | |||||
| data.moveMemory (e, e + numberToRemove, numToShift); | |||||
| numUsed -= numberToRemove; | numUsed -= numberToRemove; | ||||
| minimiseStorageAfterRemoval(); | minimiseStorageAfterRemoval(); | ||||
| @@ -994,50 +1004,6 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| /** Moves one of the values to a different position. | |||||
| This will move the value to a specified index, shuffling along | |||||
| any intervening elements as required. | |||||
| So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling | |||||
| move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. | |||||
| @param currentIndex the index of the value to be moved. If this isn't a | |||||
| valid index, then nothing will be done | |||||
| @param newIndex the index at which you'd like this value to end up. If this | |||||
| is less than zero, the value will be moved to the end | |||||
| of the array | |||||
| */ | |||||
| void move (const int currentIndex, int newIndex) noexcept | |||||
| { | |||||
| if (currentIndex != newIndex) | |||||
| { | |||||
| 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)); | |||||
| } | |||||
| } | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Reduces the amount of storage being used by the array. | /** Reduces the amount of storage being used by the array. | ||||
| @@ -1120,7 +1086,7 @@ private: | |||||
| const int numberToShift = numUsed - indexToRemove; | const int numberToShift = numUsed - indexToRemove; | ||||
| if (numberToShift > 0) | if (numberToShift > 0) | ||||
| memmove (e, e + 1, ((size_t) numberToShift) * sizeof (ElementType)); | |||||
| data.moveMemory (e, e + 1, numberToShift); | |||||
| minimiseStorageAfterRemoval(); | minimiseStorageAfterRemoval(); | ||||
| } | } | ||||
| @@ -3,7 +3,7 @@ | |||||
| This file is part of the Water library. | This file is part of the Water library. | ||||
| Copyright (c) 2016 ROLI Ltd. | Copyright (c) 2016 ROLI Ltd. | ||||
| Copyright (C) 2017 Filipe Coelho <falktx@falktx.com> | |||||
| Copyright (C) 2017-2018 Filipe Coelho <falktx@falktx.com> | |||||
| Permission is granted to use this software under the terms of the ISC license | Permission is granted to use this software under the terms of the ISC license | ||||
| http://www.isc.org/downloads/software-support-policy/isc-license/ | http://www.isc.org/downloads/software-support-policy/isc-license/ | ||||
| @@ -44,6 +44,29 @@ namespace water { | |||||
| template <class ElementType> | template <class ElementType> | ||||
| class ArrayAllocationBase | class ArrayAllocationBase | ||||
| { | { | ||||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| private: | |||||
| #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 | |||||
| template <typename T> | |||||
| struct IsTriviallyCopyable : std::integral_constant<bool, false> {}; | |||||
| #else | |||||
| template <typename T> | |||||
| 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 TriviallyCopyableBool = typename std::enable_if<IsTriviallyCopyable<T>::value, bool>::type; | |||||
| template <typename T> | |||||
| using NonTriviallyCopyableVoid = typename std::enable_if<! IsTriviallyCopyable<T>::value, void>::type; | |||||
| template <typename T> | |||||
| using NonTriviallyCopyableBool = typename std::enable_if<! IsTriviallyCopyable<T>::value, bool>::type; | |||||
| #endif // WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| /** Creates an empty array. */ | /** Creates an empty array. */ | ||||
| @@ -60,9 +83,7 @@ public: | |||||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | ||||
| ArrayAllocationBase (ArrayAllocationBase<ElementType>&& other) noexcept | ArrayAllocationBase (ArrayAllocationBase<ElementType>&& other) noexcept | ||||
| : elements (static_cast<HeapBlock<ElementType>&&> (other.elements)), | : elements (static_cast<HeapBlock<ElementType>&&> (other.elements)), | ||||
| numAllocated (other.numAllocated) | |||||
| { | |||||
| } | |||||
| numAllocated (other.numAllocated) {} | |||||
| ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType>&& other) noexcept | ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType>&& other) noexcept | ||||
| { | { | ||||
| @@ -78,27 +99,72 @@ public: | |||||
| This will retain any data currently held in the array, and either add or | This will retain any data currently held in the array, and either add or | ||||
| remove extra space at the end. | remove extra space at the end. | ||||
| @param numElements the number of elements that are needed | |||||
| @param numNewElements the number of elements that are needed | |||||
| */ | */ | ||||
| bool setAllocatedSize (const int numElements) noexcept | |||||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| template <typename T = ElementType> TriviallyCopyableBool<T> | |||||
| #else | |||||
| bool | |||||
| #endif | |||||
| setAllocatedSize (const int numNewElements) noexcept | |||||
| { | |||||
| if (numAllocated != numNewElements) | |||||
| { | |||||
| if (numNewElements > 0) | |||||
| { | |||||
| if (! elements.realloc ((size_t) numNewElements)) | |||||
| return false; | |||||
| } | |||||
| else | |||||
| { | |||||
| elements.free(); | |||||
| } | |||||
| numAllocated = numNewElements; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| template <typename T = ElementType> | |||||
| NonTriviallyCopyableBool<T> setAllocatedSize (const int numNewElements) noexcept | |||||
| { | { | ||||
| if (numAllocated != numElements) | |||||
| if (numAllocated != numNewElements) | |||||
| { | { | ||||
| if (numElements > 0) | |||||
| if (numNewElements > 0) | |||||
| { | { | ||||
| if (! elements.realloc ((size_t) numElements)) | |||||
| HeapBlock<ElementType> newElements; | |||||
| if (! newElements.malloc (numNewElements)) | |||||
| return false; | return false; | ||||
| for (int i = 0; i < numNewElements; ++i) | |||||
| { | |||||
| if (i < numAllocated) | |||||
| { | |||||
| new (newElements + i) ElementType (std::move (elements[i])); | |||||
| elements[i].~ElementType(); | |||||
| } | |||||
| else | |||||
| { | |||||
| new (newElements + i) ElementType (); | |||||
| } | |||||
| } | |||||
| elements = std::move (newElements); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| elements.free(); | elements.free(); | ||||
| } | } | ||||
| numAllocated = numElements; | |||||
| numAllocated = numNewElements; | |||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| #endif | |||||
| /** 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. | ||||
| @@ -134,6 +200,57 @@ public: | |||||
| std::swap (numAllocated, other.numAllocated); | std::swap (numAllocated, other.numAllocated); | ||||
| } | } | ||||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| template <typename T = ElementType> TriviallyCopyableVoid<T> | |||||
| #else | |||||
| void | |||||
| #endif | |||||
| moveMemory (ElementType* target, const ElementType* source, const int numElements) noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(target != nullptr,); | |||||
| CARLA_SAFE_ASSERT_RETURN(source != nullptr,); | |||||
| CARLA_SAFE_ASSERT_RETURN(target != source,); | |||||
| CARLA_SAFE_ASSERT_RETURN(numElements > 0,); | |||||
| std::memmove (target, source, ((size_t) numElements) * sizeof (ElementType)); | |||||
| } | |||||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||||
| template <typename T = ElementType> | |||||
| NonTriviallyCopyableVoid<T> moveMemory (ElementType* target, const ElementType* source, const int numElements) noexcept | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(target != nullptr,); | |||||
| CARLA_SAFE_ASSERT_RETURN(source != nullptr,); | |||||
| CARLA_SAFE_ASSERT_RETURN(target != source,); | |||||
| CARLA_SAFE_ASSERT_RETURN(numElements > 0,); | |||||
| if (target > source) | |||||
| { | |||||
| for (int i = numElements; --i >= 0;) | |||||
| { | |||||
| moveElement (target, std::move (*source)); | |||||
| ++target; | |||||
| ++source; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numElements; --i >= 0;) | |||||
| { | |||||
| moveElement (target, std::move (*source)); | |||||
| --target; | |||||
| --source; | |||||
| } | |||||
| } | |||||
| } | |||||
| void moveElement (ElementType* destination, const ElementType&& source) | |||||
| { | |||||
| destination->~ElementType(); | |||||
| new (destination) ElementType (std::move (source)); | |||||
| } | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| HeapBlock<ElementType> elements; | HeapBlock<ElementType> elements; | ||||
| int numAllocated; | int numAllocated; | ||||
| @@ -199,11 +199,6 @@ int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| void StringArray::move (const int currentIndex, const int newIndex) noexcept | |||||
| { | |||||
| strings.move (currentIndex, newIndex); | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| void StringArray::remove (const int index) | void StringArray::remove (const int index) | ||||
| { | { | ||||
| @@ -325,22 +325,6 @@ public: | |||||
| */ | */ | ||||
| void removeEmptyStrings (bool removeWhitespaceStrings = true); | void removeEmptyStrings (bool removeWhitespaceStrings = true); | ||||
| /** Moves one of the strings to a different position. | |||||
| This will move the string to a specified index, shuffling along | |||||
| any intervening elements as required. | |||||
| So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling | |||||
| move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. | |||||
| @param currentIndex the index of the value to be moved. If this isn't a | |||||
| valid index, then nothing will be done | |||||
| @param newIndex the index at which you'd like this value to end up. If this | |||||
| is less than zero, the value will be moved to the end | |||||
| of the array | |||||
| */ | |||||
| void move (int currentIndex, int newIndex) noexcept; | |||||
| /** Deletes any whitespace characters from the starts and ends of all the strings. */ | /** Deletes any whitespace characters from the starts and ends of all the strings. */ | ||||
| void trim(); | void trim(); | ||||