diff --git a/src/core/ring_buffer.hpp b/src/core/ring_buffer.hpp index a35edb08ca..253bd362d2 100644 --- a/src/core/ring_buffer.hpp +++ b/src/core/ring_buffer.hpp @@ -13,6 +13,9 @@ #include "alloc_type.hpp" #include "bitmath_func.hpp" +#include +#include + /** * Self-resizing ring-buffer * @@ -613,6 +616,42 @@ public: return this->emplace(pos, std::move(value)); } + iterator insert(ring_buffer_iterator_base pos, size_t count, const T& value) + { + if (count == 0) return iterator(pos); + + dbg_assert(pos.ring == this); + + const uint32 new_pos_start = this->setup_insert(pos.pos, count); + uint32 new_pos = new_pos_start; + for (size_t i = 0; i != count; i++) { + new (this->raw_ptr_at_pos(new_pos)) T(value); + ++new_pos; + } + return iterator(this, new_pos_start); + } + + template ::iterator_category, std::input_iterator_tag>::value>> + iterator insert(ring_buffer_iterator_base pos, InputIt first, InputIt last) + { + if (first == last) return iterator(pos); + + dbg_assert(pos.ring == this); + + const uint32 new_pos_start = this->setup_insert(pos.pos, (uint32)std::distance(first, last)); + uint32 new_pos = new_pos_start; + for (auto iter = first; iter != last; ++iter) { + new (this->raw_ptr_at_pos(new_pos)) T(*iter); + ++new_pos; + } + return iterator(this, new_pos_start); + } + + iterator insert(ring_buffer_iterator_base pos, std::initializer_list values) + { + return this->insert(pos, values.begin(), values.end()); + } + void reserve(size_t new_cap) { if (new_cap <= this->capacity()) return; diff --git a/src/tests/ring_buffer.cpp b/src/tests/ring_buffer.cpp index 8ba6d5361c..3a1d35e104 100644 --- a/src/tests/ring_buffer.cpp +++ b/src/tests/ring_buffer.cpp @@ -296,6 +296,63 @@ TEST_CASE("RingBuffer - insert in middle (end) grow") CHECK(iter == ring.begin() + 6); } +TEST_CASE("RingBuffer - insert multi at start") +{ + ring_buffer ring({ 3, 4, 5, 6, 7, 8 }); + auto iter = ring.insert(ring.begin(), { 1, 2 }); + CHECK(Matches(ring, { 1, 2, 3, 4, 5, 6, 7, 8 })); + CHECK(ring.capacity() == 8); + CHECK(iter == ring.begin()); + + iter = ring.insert(ring.begin(), { 10, 11 }); + CHECK(Matches(ring, { 10, 11, 1, 2, 3, 4, 5, 6, 7, 8 })); + CHECK(ring.capacity() == 16); + CHECK(iter == ring.begin()); + + iter = ring.insert(ring.begin(), 2, 24); + CHECK(Matches(ring, { 24, 24, 10, 11, 1, 2, 3, 4, 5, 6, 7, 8 })); + CHECK(ring.capacity() == 16); + CHECK(iter == ring.begin()); +} + +TEST_CASE("RingBuffer - insert multi at end") +{ + ring_buffer ring({ 3, 4, 5, 6, 7, 8 }); + auto iter = ring.insert(ring.end(), { 1, 2 }); + CHECK(Matches(ring, { 3, 4, 5, 6, 7, 8, 1, 2 })); + CHECK(ring.capacity() == 8); + CHECK(iter == ring.end() - 2); + + iter = ring.insert(ring.end(), { 10, 11 }); + CHECK(Matches(ring, { 3, 4, 5, 6, 7, 8, 1, 2, 10, 11 })); + CHECK(ring.capacity() == 16); + CHECK(iter == ring.end() - 2); + + iter = ring.insert(ring.end(), 2, 24); + CHECK(Matches(ring, { 3, 4, 5, 6, 7, 8, 1, 2, 10, 11, 24, 24 })); + CHECK(ring.capacity() == 16); + CHECK(iter == ring.end() - 2); +} + +TEST_CASE("RingBuffer - insert multi in middle") +{ + ring_buffer ring({ 3, 4, 5, 6, 7, 8 }); + auto iter = ring.insert(ring.begin() + 3, { 1, 2 }); + CHECK(Matches(ring, { 3, 4, 5, 1, 2, 6, 7, 8 })); + CHECK(ring.capacity() == 8); + CHECK(iter == ring.begin() + 3); + + iter = ring.insert(ring.begin() + 7, { 10, 11 }); + CHECK(Matches(ring, { 3, 4, 5, 1, 2, 6, 7, 10, 11, 8 })); + CHECK(ring.capacity() == 16); + CHECK(iter == ring.begin() + 7); + + iter = ring.insert(ring.begin() + 2, 2, 24); + CHECK(Matches(ring, { 3, 4, 24, 24, 5, 1, 2, 6, 7, 10, 11, 8 })); + CHECK(ring.capacity() == 16); + CHECK(iter == ring.begin() + 2); +} + TEST_CASE("RingBuffer - shrink to fit") { ring_buffer ring({ 3, 4, 5, 6, 7, 8 });