basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 430b25f434f63656e1b5353e78c4648ab5335ed3 |
parent | 534a0c41aed42c7a6167bf400fc1b39698b8ec0c |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Mon, 28 Apr 2025 19:16:57 +0200 |
list_pool::const_iterator and more tests
M | include/based/list.hpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ---- |
M | test/source/list_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ------ |
2 files changed, 126 insertions(+), 10 deletions(-)
diff --git a/ include/based/list.hpp b/ include/based/list.hpp
@@ -1,7 +1,6 @@
#pragma once
#include <cassert>
#include <functional>
#include <utility>
#include <vector>
@@ -104,13 +103,72 @@
public:
list_pool::list_type m_node;
};
struct const_iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = list_pool::list_type;
using value_type = list_pool::value_type;
using reference = const value_type&;
using pointer = const value_type*;
const_iterator() = default;
explicit const_iterator(const list_pool& pool)
: const_iterator(pool, pool.node_empty())
{
}
const_iterator(const list_pool& pool, list_pool::list_type node)
: m_pool(&pool)
, m_node(node)
{
}
reference operator*() const { return m_pool->value(m_node); }
pointer operator->() const { return &**this; }
const_iterator& operator++()
{
m_node = m_pool->next(m_node);
return *this;
}
const_iterator operator++(int)
{
const_iterator tmp(*this);
++*this;
return tmp;
}
friend bool operator==(const const_iterator& x, const const_iterator& y)
{
assert(x.m_pool == y.m_pool);
return x.m_node == y.m_node;
}
friend bool operator!=(const const_iterator& x, const const_iterator& y)
{
return !(x == y);
}
private:
const list_pool* m_pool;
list_pool::list_type m_node;
};
[[nodiscard]] bool is_empty(list_type x) const { return x == node_empty(); }
[[nodiscard]] list_type node_empty() const { return list_type(0); }
[[nodiscard]] const value_type& value(list_type x) const { return node(x).value; }
[[nodiscard]] const value_type& value(list_type x) const
{
return node(x).value;
}
[[nodiscard]] value_type& value(list_type x) { return node(x).value; }
[[nodiscard]] const list_type& next(list_type x) const { return node(x).next; }
[[nodiscard]] const list_type& next(list_type x) const
{
return node(x).next;
}
[[nodiscard]] list_type& next(list_type x) { return node(x).next; }
list_type free(list_type x)
@@ -153,7 +211,10 @@
public:
using queue_t = std::pair<list_type, list_type>;
[[nodiscard]] bool is_empty(const queue_t& queue) const { return is_empty(queue.first); }
[[nodiscard]] bool is_empty(const queue_t& queue) const
{
return is_empty(queue.first);
}
[[nodiscard]] queue_t queue_empty() { return {node_empty(), node_empty()}; }
[[nodiscard]] queue_t push_front(const queue_t& queue, const value_type& val)
diff --git a/ test/source/list_test.cpp b/ test/source/list_test.cpp
@@ -4,6 +4,8 @@
#include <catch2/catch_test_macros.hpp>
template class based::list_pool<std::uint8_t, std::uint8_t>;
TEST_CASE("list_pool", "[list/list_pool]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;
@@ -58,10 +60,9 @@
TEST_CASE("list_pool", "[list/list_pool]")
REQUIRE(pool.node_empty() == head);
}
TEST_CASE("list_pool iterator", "[list/list_pool/iterator]")
TEST_CASE("list_pool iterator", "[list/list_pool]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;
using iter = list_pool::iterator;
auto pool = list_pool();
auto head = pool.node_empty();
@@ -73,20 +74,25 @@
TEST_CASE("list_pool iterator", "[list/list_pool/iterator]")
SECTION("for-loop")
{
std::uint64_t sum = 0;
for (auto it = iter(pool, head); it != iter(pool); ++it) {
using iter = list_pool::iterator;
std::uint32_t sum = 0;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}
REQUIRE(sum == 0xFF * 0xFE / 2);
REQUIRE(sum == 0xFF * 0xFE);
}
SECTION("accumulate")
{
using iter = list_pool::iterator;
const auto sum = std::accumulate(
iter(pool, head),
iter(pool),
std::uint64_t {0},
std::uint32_t {0},
[](auto a, auto b)
{
return a + b;
@@ -99,6 +105,55 @@
TEST_CASE("list_pool iterator", "[list/list_pool/iterator]")
based::free_list(pool, head);
}
TEST_CASE("list_pool const iterator", "[list/list_pool]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;
auto pool = list_pool();
auto head = pool.node_empty();
static constexpr std::size_t iter_count = 0xFF;
for (std::uint8_t i = 0; i < iter_count; i++) {
head = pool.allocate(i, head);
}
SECTION("const for-loop")
{
using iter = list_pool::const_iterator;
std::uint32_t sum = 0;
for (auto it = iter(pool, head); it != iter(pool); it++) {
sum += *it.operator->();
sum += *it;
}
REQUIRE(sum == 0xFF * 0xFE);
}
SECTION("const accumulate")
{
using iter = list_pool::const_iterator;
static const auto sum =
[](const list_pool& lpool, const list_pool::list_type& lhead)
{
return std::accumulate(
iter(lpool, lhead),
iter(lpool),
std::uint32_t {0},
[](auto a, auto b)
{
return a + b;
}
);
};
REQUIRE(sum(pool, head) == 0xFF * 0xFE / 2);
}
based::free_list(pool, head);
}
TEST_CASE("list_pool queue", "[list/list_pool/queue]")
{
using list_pool = based::list_pool<std::uint8_t, std::uint8_t>;