Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add zip_map adaptor #184

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 138 additions & 49 deletions include/flux/op/zip.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,61 +26,26 @@ struct pair_or_tuple<T, U> {
template <typename... Ts>
using pair_or_tuple_t = typename pair_or_tuple<Ts...>::type;

template <sequence... Bases>
struct zip_adaptor : inline_sequence_base<zip_adaptor<Bases...>> {
private:
pair_or_tuple_t<Bases...> bases_;

friend struct sequence_traits<zip_adaptor>;

public:
constexpr explicit zip_adaptor(decays_to<Bases> auto&&... bases)
: bases_(FLUX_FWD(bases)...)
{}
};

struct zip_fn {
template <adaptable_sequence... Seqs>
[[nodiscard]]
constexpr auto operator()(Seqs&&... seqs) const
{
if constexpr (sizeof...(Seqs) == 0) {
return empty<std::tuple<>>;
} else {
return zip_adaptor<std::decay_t<Seqs>...>(FLUX_FWD(seqs)...);
}
}
};

} // namespace detail
}

template <typename... Bases>
struct sequence_traits<detail::zip_adaptor<Bases...>>
{
struct zip_traits_base {
private:
template <typename... Ts>
using tuple_t = detail::pair_or_tuple_t<Ts...>;

template <typename From, typename To>
using const_like_t = std::conditional_t<std::is_const_v<From>, To const, To>;

protected:

template <typename... Ts>
using tuple_t = detail::pair_or_tuple_t<Ts...>;

template <std::size_t I>
static constexpr decltype(auto) read1_(auto fn, auto& self, auto const& cur)
{
return fn(std::get<I>(self.bases_), std::get<I>(cur));
}

static constexpr auto read_(auto fn, auto& self, auto const& cur)
{
return [&]<std::size_t... I>(std::index_sequence<I...>) {
return tuple_t<decltype(read1_<I>(fn, self, cur))...> {
read1_<I>(fn, self, cur)...
};
}(std::index_sequence_for<Bases...>{});
}

public:
using value_type = tuple_t<value_t<Bases>...>;

static constexpr bool is_infinite = (infinite_sequence<Bases> && ...);

Expand All @@ -102,13 +67,6 @@ struct sequence_traits<detail::zip_adaptor<Bases...>>
}(std::index_sequence_for<Bases...>{});
}

template <typename Self>
requires (sequence<const_like_t<Self, Bases>> && ...)
static constexpr auto read_at(Self& self, cursor_t<Self> const& cur)
{
return read_(flux::read_at, self, cur);
}

template <typename Self>
requires (sequence<const_like_t<Self, Bases>> && ...)
static constexpr auto& inc(Self& self, cursor_t<Self>& cur)
Expand Down Expand Up @@ -169,6 +127,99 @@ struct sequence_traits<detail::zip_adaptor<Bases...>>
return std::min({flux::size(args)...});
}, self.bases_);
}
};


namespace detail {

template <sequence... Bases>
struct zip_adaptor : inline_sequence_base<zip_adaptor<Bases...>> {
private:
pair_or_tuple_t<Bases...> bases_;

friend struct sequence_traits<zip_adaptor>;
friend struct zip_traits_base<Bases...>;

public:
constexpr explicit zip_adaptor(decays_to<Bases> auto&&... bases)
: bases_(FLUX_FWD(bases)...)
{}
};

struct zip_fn {
template <adaptable_sequence... Seqs>
[[nodiscard]]
constexpr auto operator()(Seqs&&... seqs) const
{
if constexpr (sizeof...(Seqs) == 0) {
return empty<std::tuple<>>;
} else {
return zip_adaptor<std::decay_t<Seqs>...>(FLUX_FWD(seqs)...);
}
}
};

template <typename Func, sequence... Bases>
struct zip_map_adaptor : inline_sequence_base<zip_map_adaptor<Func, Bases...>> {
private:
pair_or_tuple_t<Bases...> bases_;
Func func_;

friend struct sequence_traits<zip_map_adaptor>;
friend struct zip_traits_base<Bases...>;

public:
constexpr explicit zip_map_adaptor(Func&& func, decays_to<Bases> auto&&... bases)
: bases_(FLUX_FWD(bases)...), func_(std::move(func))
{}
};

struct zip_map_fn {
template <typename Func, adaptable_sequence... Seqs>
requires std::is_invocable_v<Func, element_t<Seqs>...>
[[nodiscard]]
constexpr auto operator()(Func func, Seqs&&... seqs) const
{
if constexpr (sizeof...(Seqs) == 0) {
return empty<std::invoke_result_t<Func>>;
} else {
return zip_map_adaptor<Func, std::decay_t<Seqs>...>(std::move(func), FLUX_FWD(seqs)...);
}
}
};

} // namespace detail

template <typename... Bases>
struct sequence_traits<detail::zip_adaptor<Bases...>> : zip_traits_base<Bases...>
{
private:
using base = zip_traits_base<Bases...>;

template <typename... Ts>
using tuple_t = base::template tuple_t<Ts...>;

template <typename From, typename To>
using const_like_t = std::conditional_t<std::is_const_v<From>, To const, To>;

static constexpr auto read_(auto fn, auto& self, auto const& cur)
{
return [&]<std::size_t... I>(std::index_sequence<I...>) {
return tuple_t<decltype(base::template read1_<I>(fn, self, cur))...> {
base::template read1_<I>(fn, self, cur)...
};
}(std::index_sequence_for<Bases...>{});
}

public:
using value_type = tuple_t<value_t<Bases>...>;

template <typename Self>
requires (sequence<const_like_t<Self, Bases>> && ...)
static constexpr auto read_at(Self& self, cursor_t<Self> const& cur)
{
return read_(flux::read_at, self, cur);
}

template <typename Self>
requires (sequence<const_like_t<Self, Bases>> && ...)
Expand All @@ -190,9 +241,47 @@ struct sequence_traits<detail::zip_adaptor<Bases...>>
{
return read_(flux::move_at_unchecked, self, cur);
}

};

template <typename Func, typename... Bases>
struct sequence_traits<detail::zip_map_adaptor<Func, Bases...>> : zip_traits_base<Bases...>
{
private:
using base = zip_traits_base<Bases...>;

template <typename From, typename To>
using const_like_t = std::conditional_t<std::is_const_v<From>, To const, To>;

static constexpr auto read_(auto fn, auto& self, auto const& cur)
{
return [&]<std::size_t... I>(std::index_sequence<I...>) {
return std::invoke(self.func_,
base::template read1_<I>(fn, self, cur)...
);
}(std::index_sequence_for<Bases...>{});
}

public:
using value_type = std::invoke_result_t<Func, element_t<Bases>...>;

template <typename Self>
requires (sequence<const_like_t<Self, Bases>> && ...)
static constexpr auto read_at(Self& self, cursor_t<Self> const& cur)
{
return read_(flux::read_at, self, cur);
}

template <typename Self>
requires (sequence<const_like_t<Self, Bases>> && ...)
static constexpr auto read_at_unchecked(Self& self, cursor_t<Self> const& cur)
{
return read_(flux::read_at_unchecked, self, cur);
}
};

FLUX_EXPORT inline constexpr auto zip = detail::zip_fn{};
FLUX_EXPORT inline constexpr auto zip_map = detail::zip_map_fn{};

} // namespace flux

Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ add_executable(test-flux
test_unchecked.cpp
test_write_to.cpp
test_zip.cpp
test_zip_map.cpp
test_zip_algorithms.cpp

test_array_ptr.cpp
Expand Down
Loading
Loading