Commit ff61ae0f authored by Dominik Charousset's avatar Dominik Charousset Committed by Dominik Charousset

Fix bug in cached_queue::consume

parent d1bb08aa
......@@ -184,35 +184,42 @@ public:
/// @returns `true` if `f` consumed at least one item.
template <class F>
bool consume(F& f) noexcept(noexcept(f(std::declval<value_type&>()))) {
long consumed = 0;
if (!cache_.empty())
list_.prepend(cache_);
if (!list_.empty()) {
if (list_.empty())
return false;
long consumed = 0;
auto ptr = list_.front();
auto ts = policy().task_size(*ptr);
while (ts <= deficit_) {
CAF_ASSERT(ts > 0);
auto next = ptr->next;
dec_total_task_size(ts);
auto next = ptr->next;
// Make sure the queue is in a consistent state before calling `f` in
// case `f` recursively calls consume.
list_.before_begin()->next = next;
if (next == list_.end().ptr)
list_.end()->next = list_.before_begin().ptr;
CAF_ASSERT(total_task_size() != 0 || list_.begin() == list_.end());
/*
if (total_task_size() == 0) {
CAF_ASSERT(list_.begin() == list_.end());
list_.end()->next = list_.begin().ptr;
}
*/
// Always decrease the deficit_ counter, again because `f` is allowed
// to call consume again.
deficit_ -= ts;
auto res = f(*ptr);
if (res == task_result::skip) {
// Fix deficit and push the unconsumed item to the cache.
deficit_ += ts;
// Push the unconsumed item to the cache.
cache_.push_back(ptr);
if (list_.empty()) {
deficit_ = 0;
return consumed != 0;
}
// Fix deficit counter since we didn't actually use it.
deficit_ += ts;
} else {
deleter_type d;
d(ptr);
......@@ -230,7 +237,6 @@ public:
ptr = list_.front();
ts = policy().task_size(*ptr);
}
}
return consumed != 0;
}
......
......@@ -117,6 +117,34 @@ CAF_TEST(new_round) {
CAF_CHECK_EQUAL(queue.deficit(), 0);
}
CAF_TEST(skipping) {
// Define a function object for consuming even numbers.
std::string seq;
auto f = [&](inode& x) -> task_result {
if ((x.value & 0x01) == 1)
return task_result::skip;
seq += to_string(x);
return task_result::resume;
};
CAF_MESSAGE("make a round on an empty queue");
CAF_CHECK_EQUAL(queue.new_round(10, f), false);
CAF_MESSAGE("make a round on a queue with only odd numbers (skip all)");
fill(queue, 1, 3, 5);
CAF_CHECK_EQUAL(queue.new_round(10, f), false);
CAF_MESSAGE("make a round on a queue with an even number at the front");
fill(queue, 2);
CAF_CHECK_EQUAL(queue.new_round(10, f), true);
CAF_CHECK_EQUAL(seq, "2");
CAF_MESSAGE("make a round on a queue with an even number in between");
fill(queue, 7, 9, 4, 11, 13);
CAF_CHECK_EQUAL(queue.new_round(10, f), true);
CAF_CHECK_EQUAL(seq, "24");
CAF_MESSAGE("make a round on a queue with an even number at the back");
fill(queue, 15, 17, 6);
CAF_CHECK_EQUAL(queue.new_round(10, f), true);
CAF_CHECK_EQUAL(seq, "246");
}
CAF_TEST(alternating_consumer) {
using fun_type = std::function<task_result (inode&)>;
fun_type f;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment