Browse Source

Cleanup for Array memory use of non-trivial types

tags/v2.1-alpha1-winvst
falkTX 7 years ago
parent
commit
9032c808f3
5 changed files with 148 additions and 85 deletions
  1. +1
    -0
      source/modules/water/Makefile
  2. +20
    -54
      source/modules/water/containers/Array.h
  3. +127
    -10
      source/modules/water/containers/ArrayAllocationBase.h
  4. +0
    -5
      source/modules/water/text/StringArray.cpp
  5. +0
    -16
      source/modules/water/text/StringArray.h

+ 1
- 0
source/modules/water/Makefile View File

@@ -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)


+ 20
- 54
source/modules/water/containers/Array.h View File

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


+ 127
- 10
source/modules/water/containers/ArrayAllocationBase.h View File

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


+ 0
- 5
source/modules/water/text/StringArray.cpp View File

@@ -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)
{ {


+ 0
- 16
source/modules/water/text/StringArray.h View File

@@ -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();


Loading…
Cancel
Save