di 0.1.0
Loading...
Searching...
No Matches
access.h
Go to the documentation of this file.
1#pragma once
2
17#include "di/meta/core.h"
18#include "di/meta/operations.h"
19#include "di/meta/vocab.h"
22
23namespace di::container {
24namespace detail {
25 struct FrontFunction;
26
27 template<typename T>
28 concept CustomFront = concepts::Container<T> && concepts::TagInvocable<FrontFunction, T&>;
29
30 template<typename T>
31 concept MemberFront = concepts::Container<T> && requires(T&& container) {
32 { container.front() } -> concepts::ImplicitlyConvertibleTo<Optional<meta::ContainerReference<T>>>;
33 };
34
35 template<typename T>
36 concept BeginFront = concepts::ForwardContainer<T>;
37
38 struct FrontFunction : function::pipeline::EnablePipeline {
39 template<typename T>
40 requires(CustomFront<T> || MemberFront<T> || BeginFront<T>)
41 constexpr auto operator()(T&& container) const -> Optional<meta::ContainerReference<T>> {
42 if constexpr (CustomFront<T>) {
43 static_assert(SameAs<Optional<meta::ContainerReference<T>>, meta::TagInvokeResult<FrontFunction, T&>>,
44 "di::front() customizations must return Optional<meta::ContainerReference<T>>");
45 return function::tag_invoke(*this, container);
46 } else if constexpr (MemberFront<T>) {
47 return container.front();
48 } else {
49 if (empty(container)) {
50 return nullopt;
51 }
52 return *begin(container);
53 }
54 }
55 };
56}
57
58constexpr inline auto front = detail::FrontFunction {};
59
60namespace detail {
61 struct BackFunction;
62
63 template<typename T>
65
66 template<typename T>
67 concept MemberBack = concepts::Container<T> && requires(T&& container) {
68 { container.back() } -> concepts::ImplicitlyConvertibleTo<Optional<meta::ContainerReference<T>>>;
69 };
70
71 template<typename T>
72 concept RBeginBack = concepts::BidirectionalContainer<T> && concepts::CommonContainer<T>;
73
74 struct BackFunction : function::pipeline::EnablePipeline {
75 template<typename T>
76 requires(CustomBack<T> || MemberBack<T> || RBeginBack<T>)
77 constexpr auto operator()(T&& container) const -> Optional<meta::ContainerReference<T>> {
78 if constexpr (CustomBack<T>) {
79 static_assert(SameAs<Optional<meta::ContainerReference<T>>, meta::TagInvokeResult<BackFunction, T&>>,
80 "di::back() customizations must return Optional<meta::ContainerReference<T>>");
81 return function::tag_invoke(*this, container);
82 } else if constexpr (MemberBack<T>) {
83 return container.back();
84 } else {
85 if (empty(container)) {
86 return nullopt;
87 }
88 return *prev(end(container));
89 }
90 }
91 };
92}
93
94constexpr inline auto back = detail::BackFunction {};
95
96namespace detail {
97 struct AtFunction;
98
99 template<typename T, typename K>
101
102 template<typename T, typename K>
103 concept MemberAt = concepts::Container<T> && requires(T&& container, K&& key) {
104 { container.at(di::forward<K>(key)) } -> concepts::Optional;
105 };
106
107 template<typename T, typename K>
108 concept IndexAt = concepts::Container<T> && concepts::ConstructibleFrom<meta::IteratorSSizeType<T>, K> &&
109 requires(T& container, meta::IteratorSSizeType<T> index) {
110 { container[index] } -> SameAs<meta::ContainerReference<T>>;
111 };
112
113 template<typename T, typename K>
114 concept IteratorAt =
115 concepts::RandomAccessContainer<T> && concepts::ConstructibleFrom<meta::IteratorSSizeType<T>, K>;
116
117 struct AtFunction : function::pipeline::EnablePipeline {
118 template<typename T, typename K>
119 requires(CustomAt<T, K> || MemberAt<T, K> || IndexAt<T, K> || IteratorAt<T, K>)
120 constexpr auto operator()(T&& container, K&& key) const {
121 using SSizeType = meta::ContainerSSizeType<T>;
122 if constexpr (CustomAt<T, K>) {
123 static_assert(concepts::Optional<meta::TagInvokeResult<AtFunction, T&, K&&>>,
124 "di::at() customizations must return an Optional");
125 return function::tag_invoke(*this, container, di::forward<K>(key));
126 } else if constexpr (MemberAt<T, K>) {
127 return container.at(di::forward<K>(key));
128 } else {
129 using R = Optional<meta::ContainerReference<T>>;
130
131 auto const size = ssize(container);
132 auto const index = SSizeType(di::forward<K>(key));
133 if (index < 0 || index >= size) {
134 return R(nullopt);
135 }
136
137 if constexpr (IndexAt<T, K>) {
138 return R(container[index]);
139 } else {
140 return R(begin(container)[index]);
141 }
142 }
143 }
144 };
145}
146
147constexpr inline auto at = di::curry_back(detail::AtFunction {}, c_<2ZU>);
148
149namespace detail {
150 struct FrontUncheckedFunction : function::pipeline::EnablePipeline {
151 template<typename T>
152 constexpr auto operator()(T&& container) const -> decltype(auto)
153 requires(requires { front(di::forward<T>(container)); })
154 {
155 return *front(container);
156 }
157 };
158
159 struct BackUncheckedFunction : function::pipeline::EnablePipeline {
160 template<typename T>
161 constexpr auto operator()(T&& container) const -> decltype(auto)
162 requires(requires { back(di::forward<T>(container)); })
163 {
164 return *back(container);
165 }
166 };
167
168 struct AtUncheckedFunction {
169 template<typename T, typename K>
170 constexpr auto operator()(T&& container, K&& key) const -> decltype(auto)
171 requires(requires { at(di::forward<T>(container), di::forward<K>(key)); })
172 {
173 return *at(container, di::forward<K>(key));
174 }
175 };
176}
177
178constexpr inline auto front_unchecked = detail::FrontUncheckedFunction {};
179constexpr inline auto back_unchecked = detail::BackUncheckedFunction {};
180constexpr inline auto at_unchecked = di::curry_back(detail::AtUncheckedFunction {}, c_<2ZU>);
181}
182
183namespace di {
184using container::at;
186using container::back;
188using container::front;
190}
Definition container.h:8
Definition tag_invoke.h:33
Definition sequence.h:12
constexpr auto prev
Definition prev.h:28
constexpr auto front
Definition access.h:58
constexpr auto empty
Definition empty.h:45
constexpr auto ssize
Definition ssize.h:34
constexpr auto at
Definition access.h:147
constexpr auto back_unchecked
Definition access.h:179
constexpr auto size
Definition size.h:62
constexpr auto front_unchecked
Definition access.h:178
constexpr auto end
Definition end.h:55
constexpr auto back
Definition access.h:94
constexpr auto begin
Definition begin.h:52
constexpr auto at_unchecked
Definition access.h:180
constexpr tag_invoke_detail::TagInvokeFn tag_invoke
Definition tag_invoke.h:22
IteratorSSizeType< ContainerIterator< T > > ContainerSSizeType
Definition container_ssize_type.h:8
IteratorReference< ContainerIterator< T > > ContainerReference
Definition container_reference.h:8
decltype(container::iterator_ssize_type(types::in_place_type< meta::RemoveCVRef< T > >)) IteratorSSizeType
Definition iterator_ssize_type.h:8
decltype(di::function::tag_invoke(util::declval< Tag >(), util::declval< Args >()...)) TagInvokeResult
Definition tag_invoke.h:40
Definition any_storable.h:9
constexpr auto nullopt
Definition nullopt.h:15
constexpr auto c_
A value of type Constexpr<val>.
Definition constexpr.h:252
constexpr auto curry_back
Definition curry_back.h:141