From 226b7d943f1a70fac1c1d9bf613afddcb4c40902 Mon Sep 17 00:00:00 2001 From: Cooper Larson Date: Mon, 5 Aug 2024 14:00:52 -0600 Subject: [PATCH 1/2] fixed resize - was trying to move elements out of bounds --- include/BoundedPriorityDeque.hpp | 55 +++++++++++++++++---------- test/deque_tests.cpp | 64 ++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 20 deletions(-) diff --git a/include/BoundedPriorityDeque.hpp b/include/BoundedPriorityDeque.hpp index e6ae1eb..7f6193c 100644 --- a/include/BoundedPriorityDeque.hpp +++ b/include/BoundedPriorityDeque.hpp @@ -132,14 +132,14 @@ class BoundedPriorityDequeBase { * @return The optimal insertion index for the targeted insertion element. */ size_t binarySearch(const BoundingPair& target) const { - auto start = _head; - auto end = start + _size; + auto start = 0; + auto end = _size; while (start != end) { - size_t mid = (start + (end - start) / 2) % _k; - if (compare(_buffer[mid].key, target.key)) start = (mid + 1) % _k; + size_t mid = start + (end - start) / 2; + if (compare(_buffer[(_head + mid) % _k].key, target.key)) start = mid + 1; else end = mid; } - return start; + return (_head + start) % _k; } /** @@ -163,13 +163,17 @@ class BoundedPriorityDequeBase { } auto index = binarySearch(element); - if (index != nextIndex(_tail)) { - if (_head > 0) std::move(_buffer.begin() + _head, _buffer.begin() + index + 1, _buffer.begin() + _head - 1); - else std::move_backward(_buffer.begin() + index, _buffer.begin() + _tail + 1, _buffer.begin() + _tail + 2); + if (index == nextIndex(_tail)) _tail = nextIndex(_tail); + else if (index == prevIndex(_head)) _head = prevIndex(_head); + else if (_head <= _tail && _head > 0) { + std::move(_buffer.begin() + _head, _buffer.begin() + index + 1, _buffer.begin() + _head - 1); + --_head; + } else { + std::move_backward(_buffer.begin() + index, _buffer.begin() + _tail + 1, _buffer.begin() + _tail + 2); + ++_tail; } _buffer[index] = element; - _tail = nextIndex(_tail); ++_size; } @@ -377,19 +381,30 @@ class BoundedPriorityDequeBase { * @param k The new capacity. */ void resize(size_t k) { - _k = k; + if (k == 0) return; + + std::vector> newBuffer(k); + if (_head <= _tail) { - if (_head > 0) std::move(_buffer.begin() + _head, _buffer.begin() + _tail + 1, _buffer.begin()); - _buffer.resize(_k); - } - else { - std::vector> newBuffer(_k); - std::move(_buffer.begin() + _head, _buffer.end() + 1, newBuffer.begin()); - std::move(_buffer.begin(), _buffer.begin() + _tail + 1, newBuffer.begin() + (_k - _head - 1)); - _buffer = newBuffer; - _head = 0; - _tail = _size - 1; + size_t elementsToCopy = std::min(_size, k); + std::move(_buffer.begin() + _head, _buffer.begin() + _head + elementsToCopy, newBuffer.begin()); + _size = elementsToCopy; + } else { + size_t topSize = _k - _head; + size_t bottomSize = _tail + 1; + size_t elementsToCopyTop = std::min(topSize, k); + size_t elementsToCopyBottom = std::min(bottomSize, k - elementsToCopyTop); + + std::move(_buffer.begin() + _head, _buffer.begin() + _head + elementsToCopyTop, newBuffer.begin()); + std::move(_buffer.begin(), _buffer.begin() + elementsToCopyBottom, newBuffer.begin() + elementsToCopyTop); + + _size = elementsToCopyTop + elementsToCopyBottom; } + + _buffer.swap(newBuffer); + _k = k; + _head = 0; + _tail = _size - 1; } }; diff --git a/test/deque_tests.cpp b/test/deque_tests.cpp index 2122057..1c02f54 100644 --- a/test/deque_tests.cpp +++ b/test/deque_tests.cpp @@ -111,6 +111,70 @@ TEST(BoundedDequeTest, Merge) { ASSERT_TRUE(a.empty()); } +TEST(BoundedDequeTest, Resize) { + BoundedMinPriorityDeque deque(5); + deque.emplace(2, "two"); + deque.emplace(5, "five"); + deque.emplace(7, "seven"); + deque.emplace(12, "twelve"); + + auto two = deque.pop(); + deque.resize(2); + ASSERT_EQ(deque.topK(), 5); + ASSERT_EQ(deque.bottomK(), 7); + deque.pop(); + + deque.resize(4); + deque.emplace(1, "one"); + deque.emplace(3, "three"); + deque.emplace(9, "nine"); + deque.emplace(4, "four"); + deque.push(two); + deque.resize(4); + + ASSERT_EQ(deque.pop().value, "one"); + ASSERT_EQ(deque.pop().value, "two"); + ASSERT_EQ(deque.pop().value, "three"); + ASSERT_EQ(deque.pop().value, "four"); + ASSERT_TRUE(deque.empty()); +} + +TEST(BoundedDequeTest, ResizeCircular) { + // Initialize the buffer with a capacity of 5 + BoundedMinPriorityDeque deque(5); + + // Fill the buffer + deque.emplace(5, "five"); + deque.emplace(10, "ten"); + deque.emplace(15, "fifteen"); + deque.emplace(20, "twenty"); + deque.emplace(25, "twenty-five"); + + // Pop three elements to move the head forward + ASSERT_EQ(deque.pop().value, "five"); + ASSERT_EQ(deque.pop().value, "ten"); + ASSERT_EQ(deque.pop().value, "fifteen"); + + // Check current state of the deque + ASSERT_EQ(deque.size(), 2); + + // Continue pushing elements + deque.emplace(47, "forty-seven"); + deque.emplace(53, "fifty-three"); + deque.emplace(43, "forty-three"); + + // Resize the deque while it is wrapped around + deque.resize(4); + + // Validate the contents and order after resizing + ASSERT_EQ(deque.size(), 4); + ASSERT_EQ(deque.pop().key, 20); + ASSERT_EQ(deque.pop().key, 25); + ASSERT_EQ(deque.pop().key, 43); + ASSERT_EQ(deque.pop().key, 47); + ASSERT_TRUE(deque.empty()); +} + class ConcurrentDequeTest : public ::testing::Test { protected: BoundedMinPriorityDeque deque; From 0117091f0143fdc6f626ec555276d022c7bb7816 Mon Sep 17 00:00:00 2001 From: Cooper Larson Date: Mon, 5 Aug 2024 14:02:04 -0600 Subject: [PATCH 2/2] enforce size_t type on auto integer --- include/BoundedPriorityDeque.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/BoundedPriorityDeque.hpp b/include/BoundedPriorityDeque.hpp index 7f6193c..75db156 100644 --- a/include/BoundedPriorityDeque.hpp +++ b/include/BoundedPriorityDeque.hpp @@ -132,7 +132,7 @@ class BoundedPriorityDequeBase { * @return The optimal insertion index for the targeted insertion element. */ size_t binarySearch(const BoundingPair& target) const { - auto start = 0; + size_t start = 0; auto end = _size; while (start != end) { size_t mid = start + (end - start) / 2;