Skip to content

Commit

Permalink
Implement filter in terms of adapt
Browse files Browse the repository at this point in the history
  • Loading branch information
davidstone committed Nov 29, 2023
1 parent 35d3e07 commit 4f69631
Showing 1 changed file with 39 additions and 80 deletions.
119 changes: 39 additions & 80 deletions source/containers/algorithms/filter.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright David Stone 2018.
// Copyright David Stone 2023.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -8,124 +8,83 @@ module;
#include <bounded/assert.hpp>

#include <operators/forward.hpp>
#include <operators/returns.hpp>

export module containers.algorithms.filter;

import containers.algorithms.advance;
import containers.algorithms.find;

import containers.adapt_iterator;
import containers.adapt;
import containers.begin_end;
import containers.default_adapt_traits;
import containers.default_begin_end_size;
import containers.is_iterator;
import containers.range_value_t;
import containers.sentinel_t;
import containers.range;
import containers.reference_or_value;

import bounded;
import std_module;

using namespace bounded::literal;

namespace containers {

// TODO: use a custom begin function
using namespace bounded::literal;

template<typename Sentinel, typename UnaryPredicate>
struct filter_iterator_traits : default_begin_end_size, default_dereference, default_compare {
constexpr filter_iterator_traits(Sentinel last, UnaryPredicate condition):
struct filter_iterator_traits : default_dereference, default_compare {
constexpr filter_iterator_traits(Sentinel last, UnaryPredicate const & predicate):
m_sentinel(std::move(last)),
m_predicate(std::move(condition))
m_predicate(predicate)
{
}

constexpr auto sentinel() const -> Sentinel {
return m_sentinel;
}
constexpr auto predicate() const -> UnaryPredicate const & {
return m_predicate;
}

template<iterator Iterator>
constexpr auto add(Iterator it, bounded::constant_t<1>) const -> Iterator {
BOUNDED_ASSERT(it != m_sentinel);
return containers::find_if(
containers::next(std::move(it)),
m_sentinel,
m_predicate
m_predicate.get()
);
}
private:
[[no_unique_address]] Sentinel m_sentinel;
[[no_unique_address]] UnaryPredicate m_predicate;
[[no_unique_address]] reference_or_value<UnaryPredicate> m_predicate;
};

template<typename T>
constexpr auto is_filter_iterator_traits_impl = false;

template<typename Sentinel, typename UnaryPredicate>
constexpr auto is_filter_iterator_traits_impl<filter_iterator_traits<Sentinel, UnaryPredicate>> = true;

template<typename T>
constexpr auto is_filter_iterator_traits_impl<std::reference_wrapper<T>> = is_filter_iterator_traits_impl<T>;

template<typename T>
constexpr auto is_filter_iterator_traits_impl<T const> = is_filter_iterator_traits_impl<T>;

// TODO: Change name to something without "is"
template<typename T>
concept is_filter_iterator_traits = is_filter_iterator_traits_impl<T>;

struct filter_iterator_sentinel {
template<iterator Iterator, is_filter_iterator_traits Traits>
friend constexpr auto operator<=>(adapt_iterator<Iterator, Traits> const & lhs, filter_iterator_sentinel) OPERATORS_RETURNS(
lhs.traits().compare(lhs.base(), lhs.traits().sentinel())
)

template<iterator Iterator, is_filter_iterator_traits Traits>
friend constexpr auto operator==(adapt_iterator<Iterator, Traits> const & lhs, filter_iterator_sentinel) -> bool {
return lhs.traits().equal(lhs.base(), lhs.traits().sentinel());
}
};

constexpr auto filter_iterator_impl(iterator auto first, auto && traits) {
return containers::adapt_iterator(
containers::find_if(
std::move(first),
traits.sentinel(),
traits.predicate()
),
traits
);
}

export template<typename Range, typename UnaryPredicate>
struct filter {
constexpr filter(Range && range, UnaryPredicate predicate):
m_range(OPERATORS_FORWARD(range)),
m_traits(::containers::end(m_range), std::move(predicate))
template<typename UnaryPredicate>
struct filter_traits {
constexpr filter_traits(UnaryPredicate condition):
m_predicate(std::move(condition))
{
}

constexpr auto begin() const & {
return ::containers::filter_iterator_impl(::containers::begin(m_range), m_traits);
}
constexpr auto begin() & {
return ::containers::filter_iterator_impl(::containers::begin(m_range), m_traits);

constexpr auto get_begin(range auto && base) const {
return containers::find_if(
containers::begin(OPERATORS_FORWARD(base)),
containers::end(base),
m_predicate
);
}
constexpr auto begin() && {
return ::containers::filter_iterator_impl(::containers::begin(std::move(*this).m_range), m_traits);

static constexpr auto get_end(range auto && base) {
return containers::end(base);
}
static constexpr auto end() {
return filter_iterator_sentinel();

constexpr auto iterator_traits(range auto & base) const {
return filter_iterator_traits(
containers::end(base),
m_predicate
);
}

private:
Range m_range;
filter_iterator_traits<sentinel_t<Range &>, UnaryPredicate> m_traits;
[[no_unique_address]] UnaryPredicate m_predicate;
};

template<typename Range, typename UnaryPredicate>
filter(Range &&, UnaryPredicate) -> filter<Range, UnaryPredicate>;
export constexpr auto filter(range auto && source, auto predicate) -> range auto {
return adapt(
OPERATORS_FORWARD(source),
filter_traits(std::move(predicate))
);
}

} // namespace containers

0 comments on commit 4f69631

Please sign in to comment.