Clingo
Loading...
Searching...
No Matches
optional.hh
1#pragma once
2
3#include <clingo/util/algorithm.hh>
4#include <clingo/util/immutable_array.hh>
5
6#include <functional>
7#include <optional>
8#include <vector>
9
10namespace CppClingo::Util {
11
12namespace Detail {
13
14template <class T, class F> using transform_result = std::optional<std::remove_cv_t<std::invoke_result_t<F, T>>>;
15
16template <class T, class F>
17using and_then_result = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T>>>;
18
19template <class T, class F>
20using transform_vec_result = std::optional<std::vector<typename transform_result<T, F>::value_type>>;
21
22} // namespace Detail
23
26
28template <class T, class F> constexpr auto transform(std::optional<T> &x, F &&f) -> Detail::transform_result<T &, F> {
29 if (x.has_value()) {
30 return std::invoke(std::forward<F>(f), *x);
31 }
32 return std::nullopt;
33}
34
36template <class T, class F>
37constexpr auto transform(std::optional<T> const &x, F &&f) -> Detail::transform_result<T const &, F> {
38 if (x.has_value()) {
39 return std::invoke(std::forward<F>(f), *x);
40 }
41 return std::nullopt;
42}
43
46template <class T, class F> constexpr auto transform(std::optional<T> &&x, F &&f) -> Detail::transform_result<T, F> {
47 if (x.has_value()) {
48 return std::invoke(std::forward<F>(f), *std::move(x));
49 }
50 return std::nullopt;
51}
52
54template <class T, class F>
55constexpr auto transform(std::optional<T> const &&x, F &&f) -> Detail::transform_result<T const, F> {
56 if (x.has_value()) {
57 return std::invoke(std::forward<F>(f), *std::move(x));
58 }
59 return std::nullopt;
60}
61
63template <class T, class F> constexpr auto and_then(std::optional<T> &x, F &&f) -> Detail::and_then_result<T &, F> {
64 if (x) {
65 return std::invoke(std::forward<F>(f), *x);
66 }
67 return std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T &>>>{};
68}
69
71template <class T, class F>
72constexpr auto and_then(std::optional<T> const &x, F &&f) -> Detail::and_then_result<T const &, F> {
73 if (x) {
74 return std::invoke(std::forward<F>(f), *x);
75 }
76 return std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T const &>>>{};
77}
78
80template <class T, class F> constexpr auto and_then(std::optional<T> &&x, F &&f) -> Detail::and_then_result<T, F> {
81 if (x) {
82 return std::invoke(std::forward<F>(f), *std::move(x));
83 }
84 return std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T>>>{};
85}
86
88template <class T, class F>
89constexpr auto and_then(std::optional<T> const &&x, F &&f) -> Detail::and_then_result<T const, F> {
90 if (x) {
91 return std::invoke(std::forward<F>(f), *std::move(x));
92 }
93 return std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<F, T const>>>{};
94}
95
97template <class T, class F>
98auto transform_vec(std::optional<std::vector<T>> const &vec, F const &f)
99 -> Detail::transform_vec_result<T const &, F const &> {
100 return transform(vec, [&f](auto const &vec) {
101 typename Detail::transform_vec_result<T const &, F const &>::value_type ret;
102 ret.reserve(vec.size());
103 for (auto const &elem : vec) {
104 ret.emplace_back(std::invoke(f, elem));
105 }
106 return ret;
107 });
108}
109
111template <class T, class F>
112// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
113auto transform_vec(std::optional<std::vector<T>> &&vec, F const &f) -> Detail::transform_vec_result<T, F const &> {
114 return transform(vec, [&f](auto &vec) {
115 typename Detail::transform_vec_result<T, F const &>::value_type ret;
116 ret.reserve(vec.size());
117 for (auto &elem : vec) {
118 ret.emplace_back(std::invoke(f, std::move(elem)));
119 }
120 return ret;
121 });
122}
123
128template <class E, class S = bool> struct ResultState {
130 ResultState(S state = S{}, std::optional<E> value = std::nullopt)
131 : state{std::move(state)}, value{std::move(value)} {}
133 template <class F> ResultState(ResultState<F, S> const &res) : state{res.state}, value{res.value} {}
135 template <class F>
136 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
137 ResultState(ResultState<F, S> &&res) : state{std::move(res.state)}, value{std::move(res.value)} {}
138
140 S state = S{};
142 std::optional<E> value = std::nullopt;
143};
144
149template <class T, bool UseSpan = true> class ResultVec {
150 public:
152 using ValueType = T;
154 using Span = std::span<ValueType const>;
158 using Vector = std::vector<ValueType>;
160 using Source = std::conditional_t<UseSpan, Span, Array const &>;
162 using Iterator = std::conditional_t<UseSpan, typename Span::iterator, typename Array::const_iterator>;
164 using Result = std::conditional_t<UseSpan, Vector, Array>;
165
167 ResultVec(Source source) : source_{source}, current_{source_.begin()} {}
168
170 [[nodiscard]] auto current() const -> ValueType const & { return *current_; }
171
173 void keep() {
174 if (result_) {
175 result_->emplace_back(*current_);
176 }
177 ++current_;
178 }
180 void keep_all() {
181 if (result_) {
182 result_->insert(result_->end(), current_, source_.end());
183 }
184 current_ = source_.end();
185 }
187 void remove() {
188 if (!result_) {
189 result_ = Util::copy_n(source_, std::distance(source_.begin(), current_));
190 }
191 ++current_;
192 }
194 template <class... Args> void replace(Args &&...args) {
195 if (!result_) {
196 result_ = Util::copy_n(source_, std::distance(source_.begin(), current_));
197 }
198 result_->emplace_back(std::forward<Args>(args)...);
199 ++current_;
200 }
202 void update(std::optional<ValueType> value) {
203 if (!value.has_value()) {
204 keep();
205 } else {
206 replace(*std::move(value));
207 }
208 }
210 template <class... Args> void append(Args &&...args) {
211 if (!result_) {
212 result_ = Util::copy_n(source_, std::distance(source_.begin(), current_));
213 }
214 result_->emplace_back(std::forward<Args>(args)...);
215 }
217 template <class It> void extend(It begin, It end) {
218 if (!result_) {
219 result_ = Util::copy_n(source_, std::distance(source_.begin(), current_));
220 }
221 result_->insert(result_->end(), begin, end);
222 }
226 [[nodiscard]] auto value() const & -> Span {
227 if (result_) {
228 return *result_;
229 }
230 return source_;
231 }
233 [[nodiscard]] auto value() && -> Result {
234 if (result_) {
235 return *std::move(result_);
236 }
237 if constexpr (UseSpan) {
238 return {source_.begin(), source_.end()};
239 } else {
240 return source_;
241 }
242 }
244 [[nodiscard]] auto has_value() const -> bool { return result_.has_value(); }
246 [[nodiscard]] auto as_optional() & -> std::optional<Vector> & { return result_; }
248 [[nodiscard]] auto as_optional() && -> std::optional<Vector> { return std::move(result_); }
249
253 [[nodiscard]] auto operator*() const & -> Span { return value(); }
255 [[nodiscard]] auto operator*() && -> Result { return std::move(*this).value(); }
257 explicit operator bool() const { return has_value(); }
259 [[nodiscard]] auto complete() const { return current_ == source_.end(); }
260
261 private:
262 Source source_;
263 std::optional<Vector> result_;
264 Iterator current_;
265};
266
268template <class T> ResultVec(std::vector<T> const &) -> ResultVec<T, true>;
269
271template <class T> ResultVec(std::span<T const> const &) -> ResultVec<T, true>;
272
274template <class T> ResultVec(immutable_array<T> const &) -> ResultVec<T, false>;
275
277
278} // namespace CppClingo::Util
Helper to update a vector of elements.
Definition optional.hh:149
void keep()
Keep the current element.
Definition optional.hh:173
void remove()
Remove the current element.
Definition optional.hh:187
std::conditional_t< UseSpan, typename Span::iterator, typename Array::const_iterator > Iterator
A constant iterator to the source values.
Definition optional.hh:162
std::conditional_t< UseSpan, Vector, Array > Result
The result values.
Definition optional.hh:164
auto current() const -> ValueType const &
Get current element.
Definition optional.hh:170
auto complete() const
Check if all elements have been processed.
Definition optional.hh:259
void keep_all()
Keep all elements.
Definition optional.hh:180
std::span< ValueType const > Span
A span of values.
Definition optional.hh:154
auto value() &&-> Result
Move out the new vector or return a copy of the old one.
Definition optional.hh:233
auto value() const &-> Span
Get a const reference to the current vector.
Definition optional.hh:226
T ValueType
The value type.
Definition optional.hh:152
std::conditional_t< UseSpan, Span, Array const & > Source
The (reference to the) source values.
Definition optional.hh:160
void append(Args &&...args)
Append fresh elements.
Definition optional.hh:210
auto operator*() const &-> Span
Get a const reference to the current vector.
Definition optional.hh:253
auto has_value() const -> bool
Check if the old vector has been updated.
Definition optional.hh:244
ResultVec(Source source)
Construct a result vec to track changes to the given source.
Definition optional.hh:167
void update(std::optional< ValueType > value)
Update the current alement given the optional value.
Definition optional.hh:202
auto as_optional() &-> std::optional< Vector > &
Return a reference to the updated vector if there was a change.
Definition optional.hh:246
auto as_optional() &&-> std::optional< Vector >
Move out the updated vector.
Definition optional.hh:248
std::vector< ValueType > Vector
A vector of values.
Definition optional.hh:158
void extend(It begin, It end)
Append fresh elements.
Definition optional.hh:217
void replace(Args &&...args)
Replace the current element.
Definition optional.hh:194
auto operator*() &&-> Result
Move out the new vector or return a copy of the old one.
Definition optional.hh:255
An immutable array with efficient copying.
Definition immutable_array.hh:18
auto copy_n(Rng const &rng, size_t n) -> std::vector< typename Rng::value_type >
Return a vector with the first n elements from the given one.
Definition algorithm.hh:14
constexpr auto and_then(std::optional< T > &x, F &&f) -> Detail::and_then_result< T &, F >
Implemenatation of std::optional<T>::and_then.
Definition optional.hh:63
auto transform_vec(std::optional< std::vector< T > > const &vec, F const &f) -> Detail::transform_vec_result< T const &, F const & >
Map the given predicate over an optional vector.
Definition optional.hh:98
constexpr auto transform(std::optional< T > &x, F &&f) -> Detail::transform_result< T &, F >
Implemenatation of std::optional<T>::transform.
Definition optional.hh:28
The result of a simplification.
Definition optional.hh:128
ResultState(S state=S{}, std::optional< E > value=std::nullopt)
Construct from state and value.
Definition optional.hh:130
std::optional< E > value
An optional rewritten expression.
Definition optional.hh:142
ResultState(ResultState< F, S > const &res)
Construct from compatible result state.
Definition optional.hh:133
S state
A truth value or state.
Definition optional.hh:140
ResultState(ResultState< F, S > &&res)
Construct from compatible result state.
Definition optional.hh:137