Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions fatal/container/circular_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,9 @@ class circular_queue {
FATAL_ASSUME_LT(offset_, queue_.size());

FATAL_ASSUME_LE(chunk, count);
FATAL_ASSUME_EQ(offset_ == 0, count == chunk);
// when there are more elements to destroy beyond the first chunk, the
// first chunk must have wrapped around the buffer (resetting offset_)
FATAL_ASSUME_IF(FATAL_GT(count, chunk), FATAL_IS_TRUE(offset_ == 0));
for (auto const end = count - chunk; offset_ < end; ++offset_) {
queue_[offset_].value.~value_type();
}
Expand Down Expand Up @@ -475,13 +477,7 @@ class circular_queue {

fatal::fast_pass<size_type> size() const noexcept { return size_; }

bool empty() const noexcept {
static_assert(
noexcept(queue_.empty()),
"underlying container must provide a noexcept empty()"
);
return queue_.empty();
}
bool empty() const noexcept { return size_ == 0; }

using const_iterator = random_access_iterator<circular_queue, true>;
using iterator = random_access_iterator<circular_queue, false>;
Expand Down
63 changes: 63 additions & 0 deletions fatal/container/test/circular_queue_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,69 @@ FATAL_TEST(circular_queue, shift_to_back_by) {
}
}

FATAL_TEST(circular_queue, pop_front_count) {
circular_queue<int> q;
for (int i = 0; i < 10; ++i) {
q.push_back(i);
}
CHECK_CONTENTS(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);

// popping a prefix that does not wrap around the buffer
q.pop_front(3);
CHECK_CONTENTS(3, 4, 5, 6, 7, 8, 9);

// popping zero elements is a no-op
q.pop_front(0);
CHECK_CONTENTS(3, 4, 5, 6, 7, 8, 9);

// popping the remainder drains the queue
q.pop_front(7);
CHECK_CONTENTS();

FATAL_EXPECT_TRUE(q.empty());
}

FATAL_TEST(circular_queue, pop_front_count_wrap) {
circular_queue<int> q;
for (int i = 0; i < 10; ++i) {
q.push_back(i);
}

// drain the queue so the elements wrap around the buffer on the next pushes
q.pop_front(10);
for (int i = 0; i < 8; ++i) {
q.push_back(i);
}
CHECK_CONTENTS(0, 1, 2, 3, 4, 5, 6, 7);

// the first chunk does not reach the end of the buffer
q.pop_front(5);
CHECK_CONTENTS(5, 6, 7);

// the first chunk reaches the end of the buffer and the remainder wraps
q.pop_front(3);
CHECK_CONTENTS();

FATAL_EXPECT_TRUE(q.empty());
}

FATAL_TEST(circular_queue, empty_after_drain) {
circular_queue<int> q;
FATAL_EXPECT_TRUE(q.empty());

for (int i = 0; i < 10; ++i) {
q.push_back(i);
FATAL_EXPECT_FALSE(q.empty());
}

while (!q.empty()) {
q.pop_front();
}

FATAL_EXPECT_EQ(0, q.size());
FATAL_EXPECT_TRUE(q.empty());
}

# undef CHECK_CONTENTS

template <typename Data, typename Factory>
Expand Down