Ring buffer: Add erase
This commit is contained in:
@@ -652,6 +652,69 @@ public:
|
|||||||
return this->insert(pos, values.begin(), values.end());
|
return this->insert(pos, values.begin(), values.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 do_erase(uint32 pos, uint32 num)
|
||||||
|
{
|
||||||
|
if (pos == this->head) {
|
||||||
|
/* erase from beginning */
|
||||||
|
for (uint32 i = 0; i < num; i++) {
|
||||||
|
this->ptr_at_pos(pos + i)->~T();
|
||||||
|
}
|
||||||
|
this->head += num;
|
||||||
|
this->count -= num;
|
||||||
|
return this->head;
|
||||||
|
} else if (pos + num == this->head + this->count) {
|
||||||
|
/* erase from end */
|
||||||
|
for (uint32 i = 0; i < num; i++) {
|
||||||
|
this->ptr_at_pos(pos + i)->~T();
|
||||||
|
}
|
||||||
|
this->count -= num;
|
||||||
|
return pos;
|
||||||
|
} else if (pos - this->head < this->head + this->count - (pos + num)) {
|
||||||
|
/* closer to the beginning, shuffle beginning forwards to fill gap */
|
||||||
|
const uint32 new_head = this->head + num;
|
||||||
|
const uint32 erase_end = pos + num;
|
||||||
|
for (uint32 idx = erase_end - 1; idx != new_head - 1; idx--) {
|
||||||
|
*this->ptr_at_pos(idx) = std::move(*this->ptr_at_pos(idx - num));
|
||||||
|
}
|
||||||
|
for (uint32 idx = new_head - 1; idx != this->head - 1; idx--) {
|
||||||
|
this->ptr_at_pos(idx)->~T();
|
||||||
|
}
|
||||||
|
this->head = new_head;
|
||||||
|
this->count -= num;
|
||||||
|
return pos + num;
|
||||||
|
} else {
|
||||||
|
/* closer to the end, shuffle end backwards to fill gap */
|
||||||
|
const uint32 current_end = this->head + this->count;
|
||||||
|
const uint32 new_end = current_end - num;
|
||||||
|
for (uint32 idx = pos; idx != new_end; idx++) {
|
||||||
|
*this->ptr_at_pos(idx) = std::move(*this->ptr_at_pos(idx + num));
|
||||||
|
}
|
||||||
|
for (uint32 idx = new_end; idx != current_end; idx++) {
|
||||||
|
this->ptr_at_pos(idx)->~T();
|
||||||
|
}
|
||||||
|
this->count -= num;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator erase(ring_buffer_iterator_base pos)
|
||||||
|
{
|
||||||
|
dbg_assert(pos.ring == this);
|
||||||
|
|
||||||
|
return iterator(this, this->do_erase(pos.pos, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator erase(ring_buffer_iterator_base first, ring_buffer_iterator_base last)
|
||||||
|
{
|
||||||
|
if (first.ring == last.ring && first.pos == last.pos) return last;
|
||||||
|
|
||||||
|
dbg_assert(first.ring == this && last.ring == this);
|
||||||
|
|
||||||
|
return iterator(this, this->do_erase(first.pos, last.pos - first.pos));
|
||||||
|
}
|
||||||
|
|
||||||
void reserve(size_t new_cap)
|
void reserve(size_t new_cap)
|
||||||
{
|
{
|
||||||
if (new_cap <= this->capacity()) return;
|
if (new_cap <= this->capacity()) return;
|
||||||
|
@@ -353,6 +353,100 @@ TEST_CASE("RingBuffer - insert multi in middle")
|
|||||||
CHECK(iter == ring.begin() + 2);
|
CHECK(iter == ring.begin() + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("RingBuffer - erase")
|
||||||
|
{
|
||||||
|
ring_buffer<uint32> ring;
|
||||||
|
auto setup_ring = [&]() {
|
||||||
|
ring = ring_buffer<uint32>({ 3, 4, 5, 6, 7, 8 });
|
||||||
|
ring.push_front(2);
|
||||||
|
ring.push_front(1);
|
||||||
|
CHECK(Matches(ring, { 1, 2, 3, 4, 5, 6, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
};
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
uint32 *expect_front = &ring[1];
|
||||||
|
auto iter = ring.erase(ring.begin());
|
||||||
|
CHECK(Matches(ring, { 2, 3, 4, 5, 6, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.begin());
|
||||||
|
CHECK(expect_front == &ring[0]);
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
uint32 *expect_back = &ring[ring.size() - 2];
|
||||||
|
iter = ring.erase(ring.end() - 1);
|
||||||
|
CHECK(Matches(ring, { 1, 2, 3, 4, 5, 6, 7 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.end());
|
||||||
|
CHECK(expect_back == &ring[ring.size() - 1]);
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
expect_front = &ring[1];
|
||||||
|
iter = ring.erase(ring.begin() + 2);
|
||||||
|
CHECK(Matches(ring, { 1, 2, 4, 5, 6, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.begin() + 2);
|
||||||
|
CHECK(expect_front == &ring[0]);
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
expect_back = &ring[ring.size() - 2];
|
||||||
|
iter = ring.erase(ring.end() - 3);
|
||||||
|
CHECK(Matches(ring, { 1, 2, 3, 4, 5, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.end() - 2);
|
||||||
|
CHECK(expect_back == &ring[ring.size() - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("RingBuffer - erase multi")
|
||||||
|
{
|
||||||
|
ring_buffer<uint32> ring;
|
||||||
|
auto setup_ring = [&]() {
|
||||||
|
ring = ring_buffer<uint32>({ 3, 4, 5, 6, 7, 8 });
|
||||||
|
ring.push_front(2);
|
||||||
|
ring.push_front(1);
|
||||||
|
CHECK(Matches(ring, { 1, 2, 3, 4, 5, 6, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
};
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
uint32 *expect_front = &ring[2];
|
||||||
|
auto iter = ring.erase(ring.begin(), ring.begin() + 2);
|
||||||
|
CHECK(Matches(ring, { 3, 4, 5, 6, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.begin());
|
||||||
|
CHECK(expect_front == &ring[0]);
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
uint32 *expect_back = &ring[ring.size() - 3];
|
||||||
|
iter = ring.erase(ring.end() - 2, ring.end());
|
||||||
|
CHECK(Matches(ring, { 1, 2, 3, 4, 5, 6 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.end());
|
||||||
|
CHECK(expect_back == &ring[ring.size() - 1]);
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
expect_front = &ring[2];
|
||||||
|
iter = ring.erase(ring.begin() + 2, ring.begin() + 4);
|
||||||
|
CHECK(Matches(ring, { 1, 2, 5, 6, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.begin() + 2);
|
||||||
|
CHECK(expect_front == &ring[0]);
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
expect_back = &ring[ring.size() - 3];
|
||||||
|
iter = ring.erase(ring.end() - 4, ring.end() - 2);
|
||||||
|
CHECK(Matches(ring, { 1, 2, 3, 4, 7, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.end() - 2);
|
||||||
|
CHECK(expect_back == &ring[ring.size() - 1]);
|
||||||
|
|
||||||
|
setup_ring();
|
||||||
|
iter = ring.erase(ring.begin() + 1, ring.end() - 1);
|
||||||
|
CHECK(Matches(ring, { 1, 8 }));
|
||||||
|
CHECK(ring.capacity() == 8);
|
||||||
|
CHECK(iter == ring.begin() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("RingBuffer - shrink to fit")
|
TEST_CASE("RingBuffer - shrink to fit")
|
||||||
{
|
{
|
||||||
ring_buffer<uint32> ring({ 3, 4, 5, 6, 7, 8 });
|
ring_buffer<uint32> ring({ 3, 4, 5, 6, 7, 8 });
|
||||||
|
Reference in New Issue
Block a user