diff options
-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 | ||||
-rw-r--r-- | test/unit/testContractionState.cxx | 1 | ||||
-rw-r--r-- | test/unit/testPartitioning.cxx | 1 | ||||
-rw-r--r-- | test/unit/testRunStyles.cxx | 1 | ||||
-rw-r--r-- | test/unit/testSparseVector.cxx | 9 | ||||
-rw-r--r-- | test/unit/testSplitVector.cxx | 13 |
9 files changed, 116 insertions, 63 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; } diff --git a/test/unit/testContractionState.cxx b/test/unit/testContractionState.cxx index 989aa409d..8b401dcb6 100644 --- a/test/unit/testContractionState.cxx +++ b/test/unit/testContractionState.cxx @@ -3,6 +3,7 @@ #include <cstring> #include <stdexcept> +#include <vector> #include <algorithm> #include <memory> diff --git a/test/unit/testPartitioning.cxx b/test/unit/testPartitioning.cxx index 008c140d8..925cc9a32 100644 --- a/test/unit/testPartitioning.cxx +++ b/test/unit/testPartitioning.cxx @@ -3,6 +3,7 @@ #include <cstring> #include <stdexcept> +#include <vector> #include <algorithm> #include <memory> diff --git a/test/unit/testRunStyles.cxx b/test/unit/testRunStyles.cxx index 72840322c..e33cedb2e 100644 --- a/test/unit/testRunStyles.cxx +++ b/test/unit/testRunStyles.cxx @@ -3,6 +3,7 @@ #include <cstring> #include <stdexcept> +#include <vector> #include <algorithm> #include <memory> diff --git a/test/unit/testSparseVector.cxx b/test/unit/testSparseVector.cxx index ad0110ae0..16498397a 100644 --- a/test/unit/testSparseVector.cxx +++ b/test/unit/testSparseVector.cxx @@ -4,6 +4,7 @@ #include <cstring> #include <stdexcept> +#include <vector> #include <algorithm> #include <memory> @@ -45,9 +46,9 @@ TEST_CASE("SparseVector") { SECTION("InsertSpace") { st.InsertSpace(0, 5); REQUIRE(1 == st.Elements()); - REQUIRE(static_cast<const char *>(NULL) == st.ValueAt(0)); - REQUIRE(static_cast<const char *>(NULL) == st.ValueAt(1)); - REQUIRE(static_cast<const char *>(NULL) == st.ValueAt(4)); + REQUIRE(static_cast<const char *>(nullptr) == st.ValueAt(0)); + REQUIRE(static_cast<const char *>(nullptr) == st.ValueAt(1)); + REQUIRE(static_cast<const char *>(nullptr) == st.ValueAt(4)); st.Check(); } @@ -119,7 +120,7 @@ TEST_CASE("SparseVector") { st.SetValueAt(4, "5"); REQUIRE(2 == st.Elements()); REQUIRE("----5" == Representation(st)); - st.SetValueAt(4, NULL); + st.SetValueAt(4, nullptr); REQUIRE(1 == st.Elements()); REQUIRE("-----" == Representation(st)); st.Check(); diff --git a/test/unit/testSplitVector.cxx b/test/unit/testSplitVector.cxx index 3af51c45e..e01810d33 100644 --- a/test/unit/testSplitVector.cxx +++ b/test/unit/testSplitVector.cxx @@ -3,6 +3,7 @@ #include <cstring> #include <stdexcept> +#include <vector> #include <algorithm> #include <memory> @@ -280,11 +281,19 @@ TEST_CASE("SplitVector") { } SECTION("BufferPointer") { + // Low-level access to the data sv.InsertFromArray(0, testArray, 0, lengthTestArray); + sv.Insert(0, 99); // This moves the gap so that BufferPointer() must also move + REQUIRE(1 == sv.GapPosition()); + const int lengthAfterInsertion = 1 + lengthTestArray; + REQUIRE(lengthAfterInsertion == (sv.Length())); int *retrievePointer = sv.BufferPointer(); - for (int i=0; i<sv.Length(); i++) { - REQUIRE((i+3) == retrievePointer[i]); + for (int i=1; i<sv.Length(); i++) { + REQUIRE((i+3-1) == retrievePointer[i]); } + REQUIRE(lengthAfterInsertion == sv.Length()); + // Gap was moved to end. + REQUIRE(lengthAfterInsertion == sv.GapPosition()); } SECTION("DeleteBackAndForth") { |