userver: userver/utils/impl/projecting_view.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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