diff options
author | Neil <nyamatongwe@gmail.com> | 2017-05-21 10:26:10 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2017-05-21 10:26:10 +1000 |
commit | 8ef4f3d54de1328a1d9753f4317a5d7692a72ae8 (patch) | |
tree | d0fb1e0c6cbd0a0256066ccb9e1541d3adbdf41c /src | |
parent | 632801dae9d844bd73891a314e99161add3f47fc (diff) | |
download | scintilla-mirror-8ef4f3d54de1328a1d9753f4317a5d7692a72ae8.tar.gz |
Make SplitVector work with move-only types like unique_ptr.
Provide InsertEmpty and both const and non-const reference returning operator[].
Add and fix comments.
Diffstat (limited to 'src')
-rw-r--r-- | src/ContractionState.cxx | 1 | ||||
-rw-r--r-- | src/RunStyles.cxx | 1 | ||||
-rw-r--r-- | src/SparseVector.h | 5 | ||||
-rw-r--r-- | src/SplitVector.h | 147 |
4 files changed, 97 insertions, 57 deletions
diff --git a/src/ContractionState.cxx b/src/ContractionState.cxx index 60042bf88..6fca2ec4e 100644 --- a/src/ContractionState.cxx +++ b/src/ContractionState.cxx @@ -10,6 +10,7 @@ #include <cstring> #include <stdexcept> +#include <vector> #include <algorithm> #include <memory> diff --git a/src/RunStyles.cxx b/src/RunStyles.cxx index 38a6ba799..b0a9c1fac 100644 --- a/src/RunStyles.cxx +++ b/src/RunStyles.cxx @@ -11,6 +11,7 @@ #include <cstdarg> #include <stdexcept> +#include <vector> #include <algorithm> #include <memory> diff --git a/src/SparseVector.h b/src/SparseVector.h index 39324bdc1..ce38d0da1 100644 --- a/src/SparseVector.h +++ b/src/SparseVector.h @@ -163,7 +163,8 @@ template<> inline void SparseVector<const char *>::ClearValue(int partition) { const char *value = values->ValueAt(partition); delete []value; - values->SetValueAt(partition, NULL); + value = nullptr; + values->SetValueAt(partition, value); } template<> @@ -175,7 +176,7 @@ inline void SparseVector<const char *>::SetValueAt(int position, const char *val std::copy(value, value + len, valueCopy); CommonSetValueAt(position, valueCopy); } else { - CommonSetValueAt(position, NULL); + CommonSetValueAt(position, nullptr); } } diff --git a/src/SplitVector.h b/src/SplitVector.h index e6a7701bb..6b839b24b 100644 --- a/src/SplitVector.h +++ b/src/SplitVector.h @@ -16,11 +16,11 @@ namespace Scintilla { template <typename T> class SplitVector { protected: - T *body; - int size; + std::vector<T> body; + T empty; /// Returned as the result of out-of-bounds access. int lengthBody; int part1Length; - int gapLength; /// invariant: gapLength == size - lengthBody + int gapLength; /// invariant: gapLength == body.size() - lengthBody int growSize; /// Move the gap to a particular position so that insertion and @@ -30,16 +30,16 @@ protected: if (position != part1Length) { if (position < part1Length) { // Moving the gap towards start so moving elements towards end - std::copy_backward( - body + position, - body + part1Length, - body + gapLength + part1Length); + std::move_backward( + body.data() + position, + body.data() + part1Length, + body.data() + gapLength + part1Length); } else { // position > part1Length // Moving the gap towards end so moving elements towards start - std::copy( - body + part1Length + gapLength, - body + gapLength + position, - body + part1Length); + std::move( + body.data() + part1Length + gapLength, + body.data() + gapLength + position, + body.data() + part1Length); } part1Length = position; } @@ -49,16 +49,16 @@ protected: /// reallocating if more space needed. void RoomFor(int insertionLength) { if (gapLength <= insertionLength) { - while (growSize < size / 6) + while (growSize < static_cast<int>(body.size() / 6)) growSize *= 2; - ReAllocate(size + insertionLength + growSize); + ReAllocate(static_cast<int>(body.size()) + insertionLength + growSize); } } void Init() { - body = NULL; + body.clear(); + body.shrink_to_fit(); growSize = 8; - size = 0; lengthBody = 0; part1Length = 0; gapLength = 0; @@ -66,7 +66,7 @@ protected: public: /// Construct a split buffer. - SplitVector() { + SplitVector() : empty() { Init(); } @@ -75,8 +75,6 @@ public: void operator=(const SplitVector &) = delete; ~SplitVector() { - delete []body; - body = 0; } int GetGrowSize() const { @@ -94,61 +92,73 @@ public: if (newSize < 0) throw std::runtime_error("SplitVector::ReAllocate: negative size."); - if (newSize > size) { + if (newSize > static_cast<int>(body.size())) { // Move the gap to the end GapTo(lengthBody); - T *newBody = new T[newSize]; - if ((size != 0) && (body != 0)) { - std::copy(body, body + lengthBody, newBody); - delete []body; - } - body = newBody; - gapLength += newSize - size; - size = newSize; + gapLength += newSize - static_cast<int>(body.size()); + // RoomFor implements a growth strategy but so does vector::resize so + // ensure vector::resize allocates exactly the amount wanted by + // calling reserve first. + body.reserve(newSize); + body.resize(newSize); } } - /// Retrieve the character at a particular position. - /// Retrieving positions outside the range of the buffer returns 0. - /// The assertions here are disabled since calling code can be - /// simpler if out of range access works and returns 0. - T ValueAt(int position) const { + /// Retrieve the element at a particular position. + /// Retrieving positions outside the range of the buffer returns empty or 0. + const T& ValueAt(int position) const { if (position < part1Length) { - //PLATFORM_ASSERT(position >= 0); if (position < 0) { - return 0; + return empty; } else { return body[position]; } } else { - //PLATFORM_ASSERT(position < lengthBody); if (position >= lengthBody) { - return 0; + return empty; } else { return body[gapLength + position]; } } } - void SetValueAt(int position, T v) { + /// Set the element at a particular position. + /// Setting positions outside the range of the buffer performs no assignment + /// but asserts in debug builds. + template <typename ParamType> + void SetValueAt(int position, ParamType&& v) { if (position < part1Length) { PLATFORM_ASSERT(position >= 0); if (position < 0) { ; } else { - body[position] = v; + body[position] = std::move(v); } } else { PLATFORM_ASSERT(position < lengthBody); if (position >= lengthBody) { ; } else { - body[gapLength + position] = v; + body[gapLength + position] = std::move(v); } } } - T &operator[](int position) const { + /// Retrieve the element at a particular position. + /// The position must be within bounds or an assertion is triggered. + const T &operator[](int position) const { + PLATFORM_ASSERT(position >= 0 && position < lengthBody); + if (position < part1Length) { + return body[position]; + } else { + return body[gapLength + position]; + } + } + + /// Retrieve reference to the element at a particular position. + /// This, instead of the const variant, can be used to mutate in-place. + /// The position must be within bounds or an assertion is triggered. + T &operator[](int position) { PLATFORM_ASSERT(position >= 0 && position < lengthBody); if (position < part1Length) { return body[position]; @@ -171,7 +181,7 @@ public: } RoomFor(1); GapTo(position); - body[part1Length] = v; + body[part1Length] = std::move(v); lengthBody++; part1Length++; gapLength--; @@ -187,7 +197,28 @@ public: } RoomFor(insertLength); GapTo(position); - std::fill(&body[part1Length], &body[part1Length + insertLength], v); + std::fill(body.data() + part1Length, body.data() + part1Length + insertLength, v); + lengthBody += insertLength; + part1Length += insertLength; + gapLength -= insertLength; + } + } + + /// Add some new empty elements. + /// InsertValue is good for value objects but not for unique_ptr objects + /// since they can only be moved from once. + void InsertEmpty(int position, int insertLength) { + PLATFORM_ASSERT((position >= 0) && (position <= lengthBody)); + if (insertLength > 0) { + if ((position < 0) || (position > lengthBody)) { + return; + } + RoomFor(insertLength); + GapTo(position); + for (int elem = part1Length; elem < part1Length + insertLength; elem++) { + T emptyOne = {}; + body[elem] = std::move(emptyOne); + } lengthBody += insertLength; part1Length += insertLength; gapLength -= insertLength; @@ -198,7 +229,7 @@ public: /// appending zero valued elements if needed. void EnsureLength(int wantedLength) { if (Length() < wantedLength) { - InsertValue(Length(), wantedLength - Length(), 0); + InsertEmpty(Length(), wantedLength - Length()); } } @@ -211,7 +242,7 @@ public: } RoomFor(insertLength); GapTo(positionToInsert); - std::copy(s + positionFrom, s + positionFrom + insertLength, body + part1Length); + std::copy(s + positionFrom, s + positionFrom + insertLength, body.data() + part1Length); lengthBody += insertLength; part1Length += insertLength; gapLength -= insertLength; @@ -236,7 +267,8 @@ public: } if ((position == 0) && (deleteLength == lengthBody)) { // Full deallocation returns storage and is faster - delete []body; + body.clear(); + body.shrink_to_fit(); Init(); } else if (deleteLength > 0) { GapTo(position); @@ -247,10 +279,10 @@ public: /// Delete all the buffer contents. void DeleteAll() { - DeleteRange(0, lengthBody); + DeleteRange(0, static_cast<int>(lengthBody)); } - // Retrieve a range of elements into an array + /// Retrieve a range of elements into an array void GetRange(T *buffer, int position, int retrieveLength) const { // Split into up to 2 ranges, before and after the split then use memcpy on each. int range1Length = 0; @@ -260,34 +292,39 @@ public: if (range1Length > part1AfterPosition) range1Length = part1AfterPosition; } - std::copy(body + position, body + position + range1Length, buffer); + std::copy(body.data() + position, body.data() + position + range1Length, buffer); buffer += range1Length; - position = position + range1Length + gapLength; + position = static_cast<int>(position + range1Length + gapLength); int range2Length = retrieveLength - range1Length; - std::copy(body + position, body + position + range2Length, buffer); + std::copy(body.data() + position, body.data() + position + range2Length, buffer); } + /// Compact the buffer and return a pointer to the first element. T *BufferPointer() { RoomFor(1); GapTo(lengthBody); - body[lengthBody] = 0; - return body; + T emptyOne = {}; + body[lengthBody] = std::move(emptyOne); + return body.data(); } + /// Return a pointer to a range of elements, first rearranging the buffer if + /// needed to make that range contiguous. T *RangePointer(int position, int rangeLength) { if (position < part1Length) { if ((position + rangeLength) > part1Length) { // Range overlaps gap, so move gap to start of range. GapTo(position); - return body + position + gapLength; + return body.data() + position + gapLength; } else { - return body + position; + return body.data() + position; } } else { - return body + position + gapLength; + return body.data() + position + gapLength; } } + /// Return the position of the gap within the buffer. int GapPosition() const { return part1Length; } |