Skip to content

Commit b1f016f

Browse files
committed
Implement adjacent view functionality
1 parent 4f7496b commit b1f016f

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

include/kf/AdjacentView.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
#include <ranges>
3+
#include <array>
4+
5+
namespace kf
6+
{
7+
template <std::ranges::forward_range Range, size_t N>
8+
requires std::ranges::view<Range> && (N > 0) && std::ranges::common_range<Range>
9+
class AdjacentView : public std::ranges::view_interface<AdjacentView<Range, N>>
10+
{
11+
public:
12+
AdjacentView() requires std::default_initializable<Range> = default;
13+
14+
explicit AdjacentView(Range base)
15+
: m_base(std::move(base))
16+
{
17+
}
18+
19+
constexpr auto begin()
20+
{
21+
return Iterator{ std::ranges::begin(m_base), std::ranges::end(m_base) };
22+
}
23+
24+
constexpr auto end()
25+
{
26+
return Iterator{ AsSentinel{}, std::ranges::end(m_base) };
27+
}
28+
29+
private:
30+
struct AsSentinel
31+
{
32+
explicit AsSentinel() = default;
33+
};
34+
35+
struct Iterator
36+
{
37+
using BaseIterator = std::ranges::iterator_t<Range>;
38+
std::array<BaseIterator, N> m_current{};
39+
40+
constexpr Iterator(BaseIterator first, std::ranges::sentinel_t<Range> last)
41+
{
42+
m_current.front() = first;
43+
for (size_t i = 1; i < N; ++i)
44+
{
45+
std::ranges::advance(first, 1, last);
46+
m_current[i] = first;
47+
}
48+
}
49+
50+
constexpr Iterator(AsSentinel, BaseIterator last)
51+
{
52+
if constexpr (!std::ranges::bidirectional_range<Range>)
53+
{
54+
m_current.fill(last);
55+
}
56+
else
57+
{
58+
m_current.back() = last;
59+
for (size_t i = 1; i < N; ++i)
60+
{
61+
std::ranges::advance(last, -1, last);
62+
m_current[N - 1 - i] = last;
63+
}
64+
}
65+
}
66+
67+
template <std::size_t... I>
68+
constexpr auto arrayToTuple(const decltype(m_current)& arr, std::index_sequence<I...>) const
69+
{
70+
return std::tie((*arr[I])...);
71+
}
72+
73+
constexpr auto transformToTuple(const decltype(m_current)& arr) const
74+
{
75+
return arrayToTuple(arr, std::make_index_sequence<N>{});
76+
}
77+
78+
constexpr auto operator*() const
79+
{
80+
return transformToTuple(m_current);
81+
}
82+
83+
constexpr Iterator& operator++()
84+
{
85+
for (BaseIterator& iter : m_current)
86+
{
87+
++iter;
88+
}
89+
return *this;
90+
}
91+
92+
constexpr bool operator==(const Iterator& other) const
93+
{
94+
return m_current.back() == other.m_current.back();
95+
}
96+
};
97+
98+
private:
99+
Range m_base{};
100+
};
101+
102+
template <size_t N>
103+
class AdjacentFn
104+
{
105+
public:
106+
template <std::ranges::forward_range R>
107+
requires std::ranges::viewable_range<R>
108+
auto operator()(R&& r) const
109+
{
110+
return AdjacentView<std::views::all_t<R>, N>(std::forward<R>(r));
111+
}
112+
};
113+
114+
template <size_t N>
115+
constexpr AdjacentFn<N> adjacent;
116+
inline constexpr AdjacentFn<2> pairwise;
117+
}

0 commit comments

Comments
 (0)