diff --git a/src/util/FilteredContainer.hxx b/src/util/FilteredContainer.hxx new file mode 100644 index 000000000..6e2d8abfa --- /dev/null +++ b/src/util/FilteredContainer.hxx @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: BSD-2-Clause +// author: Max Kellermann + +#pragma once + +#include // for std::iterator_traits + +/** + * A container wrapper which returns only elements for which a second + * container returns true. + */ +template +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; + + 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; + + [[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(); + } +};