userver: userver/utils/impl/projecting_view.hpp Source File
Loading...
Searching...
No Matches
projecting_view.hpp
1#pragma once
2
3#include <iterator>
4#include <type_traits>
5
6USERVER_NAMESPACE_BEGIN
7
8namespace utils::impl {
9
10struct first {
11 template <class T>
12 auto operator()(T& value) const noexcept -> decltype(value.first)& {
13 return value.first;
14 }
15};
16
17struct second {
18 template <class T>
19 auto operator()(T& value) const noexcept -> decltype(value.second)& {
20 return value.second;
21 }
22};
23
24template <class BaseIterator, class Projection>
25class ProjectingIterator : Projection {
26 public:
27 using iterator_category = std::forward_iterator_tag;
28 using value_type = std::decay_t<std::invoke_result_t<
29 Projection, typename std::iterator_traits<BaseIterator>::value_type&>>;
30 using difference_type =
31 typename std::iterator_traits<BaseIterator>::difference_type;
32 using reference = value_type&;
33 using pointer = value_type*;
34
35 ProjectingIterator() = default;
36 explicit ProjectingIterator(BaseIterator it) : it_(std::move(it)) {}
37 ProjectingIterator(BaseIterator it, Projection proj)
38 : Projection(std::move(proj)), it_(std::move(it)) {}
39 ProjectingIterator(const ProjectingIterator&) = default;
40 ProjectingIterator(ProjectingIterator&&) noexcept = default;
41 ProjectingIterator& operator=(const ProjectingIterator&) = default;
42 ProjectingIterator& operator=(ProjectingIterator&&) noexcept = default;
43
44 bool operator==(ProjectingIterator other) const { return it_ == other.it_; }
45 bool operator!=(ProjectingIterator other) const { return it_ != other.it_; }
46
47 ProjectingIterator& operator++() {
48 ++it_;
49 return *this;
50 }
51
52 ProjectingIterator operator++(int) { return ProjectingIterator{it_++}; }
53
54 decltype(auto) operator*() const { return Projection::operator()(*it_); }
55
56 private:
57 BaseIterator it_;
58};
59
60// A backport of std::ranges::transform_view.
61template <class Container, class Projection>
62class ProjectingView : private Projection {
63 public:
64 using BaseConstIterator = typename Container::const_iterator;
65 using BaseIterator =
66 std::conditional_t<std::is_const_v<Container>, BaseConstIterator,
67 typename Container::iterator>;
68
69 using const_iterator = ProjectingIterator<BaseConstIterator, Projection>;
70 using value_type = typename const_iterator::value_type;
71
72 explicit ProjectingView(Container& container) noexcept
73 : container_(container) {}
74
75 ProjectingView(Container& container, Projection proj) noexcept
76 : Projection(std::move(proj)), container_(container) {}
77
78 auto cbegin() const {
79 return ProjectingIterator<BaseConstIterator, Projection>{
80 container_.cbegin(), static_cast<const Projection&>(*this)};
81 }
82
83 auto cend() const {
84 return ProjectingIterator<BaseConstIterator, Projection>{
85 container_.cend(), static_cast<const Projection&>(*this)};
86 }
87
88 auto begin() {
89 return ProjectingIterator<BaseIterator, Projection>{
90 container_.begin(), static_cast<const Projection&>(*this)};
91 }
92
93 auto end() {
94 return ProjectingIterator<BaseIterator, Projection>{
95 container_.end(), static_cast<const Projection&>(*this)};
96 }
97
98 auto begin() const { return cbegin(); }
99 auto end() const { return cend(); }
100
101 private:
102 Container& container_;
103};
104
105// A backport of std::ranges::views::keys.
106template <class Container>
107ProjectingView<const Container, impl::first> MakeKeysView(const Container& c) {
108 return ProjectingView<const Container, impl::first>{c};
109}
110
111// A backport of std::ranges::views::values.
112template <class Container>
113ProjectingView<Container, impl::second> MakeValuesView(Container& c) {
114 return ProjectingView<Container, impl::second>{c};
115}
116
117} // namespace utils::impl
118
119USERVER_NAMESPACE_END