Skip to content

Commit a414138

Browse files
maliysergeySerhiiMalyiSergiusTheBest
authored
Implement adjacent view functionality (#8)
* Implement adjacent view functionality * Move adjacent view header to mimic STL files structure * Add some improvements and tests --------- Co-authored-by: Serhii Malyi <maliy.sergey@apriorit.com> Co-authored-by: Sergey Podobry <sergius@apriorit.com>
1 parent 3e65855 commit a414138

File tree

5 files changed

+173
-0
lines changed

5 files changed

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

test/AdjacentView.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include "pch.h"
2+
#include <kf/stl/backport/ranges/ranges>
3+
4+
SCENARIO("views::adjacent")
5+
{
6+
GIVEN("array with 4 elements: 1,2,3,4")
7+
{
8+
std::array<int, 4> arr = { 1, 2, 3, 4 };
9+
10+
WHEN("create adjacent view for 1 elements")
11+
{
12+
auto view = arr | kf::views::adjacent<1>;
13+
14+
THEN("view contains 4 tuples: (1)(2)(3)(4)")
15+
{
16+
std::array<std::tuple<int>, 4> expected = { { {1}, {2}, {3}, {4} } };
17+
18+
REQUIRE(std::equal(view.begin(), view.end(), expected.begin(), expected.end()));
19+
}
20+
}
21+
22+
WHEN("create adjacent view for 2 elements")
23+
{
24+
auto view = arr | kf::views::adjacent<2>;
25+
26+
THEN("view contains 3 tuples: (1,2)(2,3)(3,4)")
27+
{
28+
std::array<std::tuple<int, int>, 3> expected = { { {1, 2}, {2, 3}, {3, 4} } };
29+
30+
REQUIRE(std::equal(view.begin(), view.end(), expected.begin(), expected.end()));
31+
}
32+
}
33+
}
34+
}

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ find_package(WDK REQUIRED)
3838
wdk_add_driver(kf-test WINVER NTDDI_WIN10 STL
3939
pch.h
4040
pch.cpp
41+
AdjacentView.cpp
4142
HexTest.cpp
4243
Vector.cpp
4344
)

test/pch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include <ntifs.h>
3+
#include <algorithm>
34
#include <array>
45
#include <kmtest/kmtest.h>
56

0 commit comments

Comments
 (0)