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_files:%.o=%.d)
-include $(OBJS_posix32:%.o=%.d)
-include $(OBJS_posix64:%.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.
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
http://www.isc.org/downloads/software-support-policy/isc-license/
@@ -416,7 +416,7 @@ public:
const int numberToMove = numUsed - indexToInsertAt;
if (numberToMove > 0)
std::memmove (insertPos + 1, insertPos, ((size_t) numberToMove) * sizeof (ElementType));
data.moveMemory (insertPos + 1, insertPos, numberToMove);
new (insertPos) ElementType (newElement);
++numUsed;
@@ -441,19 +441,21 @@ public:
@param numberOfTimesToInsertIt how many copies of the value to insert
@see insert, add, addSorted, set
*/
void insertMultiple (int indexToInsertAt, ParameterType newElement,
bool insertMultiple (int indexToInsertAt, ParameterType newElement,
int numberOfTimesToInsertIt)
{
if (numberOfTimesToInsertIt > 0)
{
data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt);
if (! data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt))
return false;
ElementType* insertPos;
if (isPositiveAndBelow (indexToInsertAt, numUsed))
{
insertPos = data.elements + indexToInsertAt;
const int numberToMove = numUsed - indexToInsertAt;
memmove (insertPos + numberOfTimesToInsertIt, insertPos, ((size_t) numberToMove) * sizeof (ElementType));
data.moveMemory (insertPos + numberOfTimesToInsertIt, insertPos, numberToMove);
}
else
{
@@ -469,8 +471,11 @@ public:
// 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.
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
@see insert, add, addSorted, set
*/
void insertArray (int indexToInsertAt,
bool insertArray (int indexToInsertAt,
const ElementType* newElements,
int numberOfElements)
{
if (numberOfElements > 0)
{
data.ensureAllocatedSize (numUsed + numberOfElements);
if (! data.ensureAllocatedSize (numUsed + numberOfElements))
return false;
ElementType* insertPos = data.elements;
if (isPositiveAndBelow (indexToInsertAt, numUsed))
{
insertPos += 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
{
@@ -508,7 +515,10 @@ public:
while (--numberOfElements >= 0)
new (insertPos++) ElementType (*newElements++);
}
return true;
}
#endif
/** Appends a new element at the end of the array as long as the array doesn't
already contain it.
@@ -903,7 +913,7 @@ public:
const int numToShift = numUsed - endIndex;
if (numToShift > 0)
memmove (e, e + numberToRemove, ((size_t) numToShift) * sizeof (ElementType));
data.moveMemory (e, e + numberToRemove, numToShift);
numUsed -= numberToRemove;
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.
@@ -1120,7 +1086,7 @@ private:
const int numberToShift = numUsed - indexToRemove;
if (numberToShift > 0)
memmove (e, e + 1, ((size_t) numberToShift) * sizeof (ElementType));
data.moveMemory (e, e + 1, numberToShift);
minimiseStorageAfterRemoval();
}


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

@@ -3,7 +3,7 @@
This file is part of the Water library.
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
http://www.isc.org/downloads/software-support-policy/isc-license/
@@ -44,6 +44,29 @@ namespace water {
template <class ElementType>
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:
//==============================================================================
/** Creates an empty array. */
@@ -60,9 +83,7 @@ public:
#if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS
ArrayAllocationBase (ArrayAllocationBase<ElementType>&& other) noexcept
: elements (static_cast<HeapBlock<ElementType>&&> (other.elements)),
numAllocated (other.numAllocated)
{
}
numAllocated (other.numAllocated) {}
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
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;
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
{
elements.free();
}
numAllocated = numElements;
numAllocated = numNewElements;
}
return true;
}
#endif
/** Increases the amount of storage allocated if it is less than a given amount.
@@ -134,6 +200,57 @@ public:
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;
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;
}
void StringArray::move (const int currentIndex, const int newIndex) noexcept
{
strings.move (currentIndex, newIndex);
}
//==============================================================================
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);
/** 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. */
void trim();


Loading…
Cancel
Save