util/FilteredContainer: new class

This commit is contained in:
Max Kellermann 2024-07-10 22:04:34 +02:00
parent 9210705598
commit f6a687dc2b
1 changed files with 116 additions and 0 deletions

View File

@ -0,0 +1,116 @@
// SPDX-License-Identifier: BSD-2-Clause
// author: Max Kellermann <max.kellermann@gmail.com>
#pragma once
#include <iterator> // for std::iterator_traits
/**
* A container wrapper which returns only elements for which a second
* container returns true.
*/
template<std::input_iterator AB, typename AE,
std::input_iterator BB>
class FilteredContainer {
[[no_unique_address]]
AB a_begin;
[[no_unique_address]]
AE a_end;
[[no_unique_address]]
BB b_begin;
struct end_iterator {
using Traits = std::iterator_traits<AE>;
using iterator_category = typename Traits::iterator_category;
using difference_type = typename Traits::difference_type;
using value_type = typename Traits::value_type;
using pointer = typename Traits::pointer;
using reference = typename Traits::reference;
AE a;
};
public:
explicit constexpr FilteredContainer(AB _a_begin, AE _a_end, BB _b_begin) noexcept
:a_begin(_a_begin), a_end(_a_end), b_begin(_b_begin) {}
class iterator {
using Traits = std::iterator_traits<AB>;
[[no_unique_address]]
AB a;
[[no_unique_address]]
AE a_end;
[[no_unique_address]]
BB b;
public:
using iterator_category = typename std::forward_iterator_tag;
using difference_type = typename Traits::difference_type;
using value_type = typename Traits::value_type;
using pointer = typename Traits::pointer;
using reference = typename Traits::reference;
explicit constexpr iterator(AB _a, AE _a_end, BB _b) noexcept
:a(_a), a_end(_a_end), b(_b) {}
constexpr void FindEnabled() noexcept {
while (a != a_end && !*b) {
++a;
++b;
}
}
constexpr bool operator==(const iterator &other) const noexcept {
return a == other.a;
}
constexpr bool operator==(const end_iterator &other) const noexcept {
return a == other.a;
}
constexpr auto &operator++() noexcept {
++a;
++b;
FindEnabled();
return *this;
}
constexpr auto operator++(int) noexcept {
auto old = *this;
++*this;
return old;
}
reference operator*() const noexcept {
return a.operator*();
}
pointer operator->() const noexcept {
return a.operator->();
}
};
constexpr iterator begin() const noexcept {
iterator it{a_begin, a_end, b_begin};
it.FindEnabled();
return it;
}
constexpr end_iterator end() const noexcept {
return {a_end};
}
constexpr iterator cbegin() const noexcept {
return begin();
}
constexpr end_iterator cend() const noexcept {
return end();
}
};