1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef _PANDA_LAZY_HPP
17 #define _PANDA_LAZY_HPP
18
19 #include "callable.h"
20
21 #include <optional>
22 #include <functional>
23 #include <tuple>
24
25 #include <type_traits>
26
27 namespace panda::verifier {
28
29 template <typename Value>
30 struct IsLazyStreamValue {
31 using type = Value;
32 template <typename U, decltype(static_cast<bool>(*(static_cast<U *>(nullptr)))) *>
33 struct FS {
34 };
35 template <typename U>
36 static char F(FS<U, nullptr> *);
37 template <typename U>
38 static int F(...);
39
40 template <typename U, std::decay_t<decltype(*((*(static_cast<U *>(nullptr)))))> *>
41 struct GS {
42 };
43 template <typename U>
44 static char G(GS<U, nullptr> *);
45 template <typename U>
46 static int G(...);
47
48 static constexpr bool value = sizeof(F<Value>(0)) == 1 && sizeof(G<Value>(0)) == 1;
49 };
50
51 template <typename Stream>
52 struct IsLazyStream {
53 using type = Stream;
54 static constexpr bool value = IsLazyStreamValue<decltype((*(static_cast<Stream *>(nullptr)))())>::value;
55 };
56
57 template <typename V>
58 struct LazyStreamValue {
59 using type = V;
60 using value_type = decltype(*(*(static_cast<V *>(nullptr))));
61 };
62
63 template <typename V>
64 using LazyStreamValueType = typename LazyStreamValue<V>::value_type;
65
66 template <typename C>
LazyFetch(C & c)67 auto LazyFetch(C &c)
68 {
69 return [end = c.end(), it = c.begin()]() mutable -> std::optional<std::decay_t<decltype(*(c.begin()))>> {
70 if (it != end) {
71 return *(it++);
72 }
73 return std::nullopt;
74 };
75 }
76
77 template <typename C>
LazyFetch(const C & c)78 auto LazyFetch(const C &c)
79 {
80 return [end = c.end(), it = c.begin()]() mutable -> std::optional<std::decay_t<decltype(*(c.begin()))>> {
81 if (it != end) {
82 return *(it++);
83 }
84 return std::nullopt;
85 };
86 }
87
88 template <typename C>
ConstLazyFetch(const C & c)89 auto ConstLazyFetch(const C &c)
90 {
91 return [cend = c.cend(), it = c.cbegin()]() mutable -> std::optional<std::decay_t<decltype(*(c.cbegin()))>> {
92 if (it != cend) {
93 return *(it++);
94 }
95 return std::nullopt;
96 };
97 }
98
99 template <typename C>
RefLazyFetch(C & c)100 auto RefLazyFetch(C &c)
101 {
102 return [end = c.end(), it = c.begin()]() mutable -> std::optional<decltype(std::ref(*(c.begin())))> {
103 if (it != end) {
104 return {std::ref(*(it++))};
105 }
106 return std::nullopt;
107 };
108 }
109
110 template <typename C>
RefConstLazyFetch(const C & c)111 auto RefConstLazyFetch(const C &c)
112 {
113 return [cend = c.cend(), it = c.cbegin()]() mutable -> std::optional<decltype(std::cref(*(c.cbegin())))> {
114 if (it != cend) {
115 return {std::cref(*(it++))};
116 }
117 return std::nullopt;
118 };
119 }
120
121 template <typename F, typename L, std::enable_if_t<IsLazyStream<F>::value, int> = 0>
Transform(F fetcher,L converter)122 auto Transform(F fetcher, L converter)
123 {
124 return [fetcher, converter]() mutable -> std::optional<decltype(converter(*fetcher()))> {
125 if (auto val = fetcher()) {
126 return {converter(*val)};
127 }
128 return std::nullopt;
129 };
130 }
131
132 template <typename F, typename L, std::enable_if_t<IsLazyStream<F>::value, int> = 0>
Filter(F fetcher,L filter)133 auto Filter(F fetcher, L filter)
134 {
135 return [fetcher, filter]() mutable -> decltype(fetcher()) {
136 while (auto val = fetcher()) {
137 if (filter(*val)) {
138 return val;
139 }
140 }
141 return std::nullopt;
142 };
143 }
144
145 template <typename F, std::enable_if_t<IsLazyStream<F>::value, int> = 0>
146 auto Enumerate(F fetcher, size_t from = 0)
147 {
148 return Transform(fetcher, [idx = from](auto v) mutable { return std::tuple {idx++, v}; });
149 }
150
151 template <typename C>
IndicesOf(const C & c)152 auto IndicesOf(const C &c)
153 {
154 size_t from = 0;
155 size_t to = c.size();
156 return [from, to]() mutable -> std::optional<size_t> {
157 if (from < to) {
158 return {from++};
159 }
160 return std::nullopt;
161 };
162 }
163
164 template <typename Fetcher, typename Func, std::enable_if_t<IsLazyStream<Fetcher>::value, int> = 0>
ForEachCond(Fetcher fetcher,Func func)165 void ForEachCond(Fetcher fetcher, Func func)
166 {
167 while (auto val = fetcher()) {
168 if (!func(*val)) {
169 return;
170 }
171 }
172 }
173
174 template <typename Fetcher, typename Func, std::enable_if_t<IsLazyStream<Fetcher>::value, int> = 0>
ForEach(Fetcher fetcher,Func func)175 void ForEach(Fetcher fetcher, Func func)
176 {
177 while (auto val = fetcher()) {
178 func(*val);
179 }
180 }
181
182 template <typename Fetcher, typename Accum, typename Func, std::enable_if_t<IsLazyStream<Fetcher>::value, int> = 0>
FoldLeft(Fetcher fetcher,Accum accum,Func func)183 Accum FoldLeft(Fetcher fetcher, Accum accum, Func func)
184 {
185 while (auto val = fetcher()) {
186 accum = func(accum, *val);
187 }
188 return accum;
189 }
190
191 template <typename F, std::enable_if_t<IsLazyStream<F>::value, int> = 0>
Iterable(F fetcher)192 auto Iterable(F fetcher)
193 {
194 class SomeClass {
195 public:
196 explicit SomeClass(F f) : Fetcher_ {f} {};
197 class Iterator {
198 public:
199 explicit Iterator(std::optional<F> f) : Fetcher_ {std::move(f)}
200 {
201 if (Fetcher_) {
202 val_ = (*Fetcher_)();
203 }
204 }
205 Iterator &operator++()
206 {
207 val_ = (*Fetcher_)();
208 return *this;
209 }
210 bool operator==([[maybe_unused]] const Iterator &it)
211 {
212 return !static_cast<bool>(val_);
213 }
214 bool operator!=([[maybe_unused]] const Iterator &it)
215 {
216 return static_cast<bool>(val_);
217 }
218 auto operator*()
219 {
220 return *val_;
221 }
222
223 private:
224 std::optional<F> Fetcher_;
225 decltype((*Fetcher_)()) val_;
226 };
227 Iterator end() // NOLINT(readability-identifier-naming)
228 {
229 return Iterator {{}};
230 }
231 Iterator begin() // NOLINT(readability-identifier-naming)
232 {
233 return Iterator {Fetcher_};
234 }
235
236 private:
237 F Fetcher_;
238 };
239 return SomeClass {fetcher};
240 }
241
242 template <typename Prev, typename Next,
243 std::enable_if_t<std::is_same<decltype((*static_cast<Prev *>(nullptr))()),
244 decltype((*static_cast<Next *>(nullptr))())>::value,
245 int> = 0,
246 std::enable_if_t<IsLazyStream<Prev>::value, int> = 0>
247 auto operator+(Prev prev, Next next)
248 {
249 return [prev, next, first = true]() mutable {
250 if (first) {
251 auto val = prev();
252 if (val) {
253 return val;
254 }
255 first = false;
256 }
257 auto val = next();
258 return val;
259 };
260 }
261
262 template <typename C, typename S>
263 C ContainerOf(S stream, typename std::decay<decltype(
264 (*static_cast<C *>(nullptr))
265 .push_back(*static_cast<std::decay_t<decltype(*((*(static_cast<S *>(nullptr)))()))> *>(
266 nullptr)))>::type *tmp = nullptr)
267 {
268 (void)tmp;
269 C c;
270 while (auto val = stream()) {
271 c.push_back(*val);
272 }
273 return c;
274 }
275
276 template <typename C, typename S>
277 C ContainerOf(
278 S stream,
279 typename std::decay<decltype(
280 (*static_cast<C *>(nullptr))
281 .insert(*static_cast<std::decay_t<decltype(*((*(static_cast<S *>(nullptr)))()))> *>(nullptr)))>::type *tmp =
282 nullptr)
283 {
284 (void)tmp;
285 C c;
286 while (auto val = stream()) {
287 c.insert(*val);
288 }
289 return c;
290 }
291
292 template <template <typename...> class UnorderedSet, typename Fetcher,
293 std::enable_if_t<IsLazyStream<Fetcher>::value, int> = 0>
Uniq(Fetcher fetcher)294 auto Uniq(Fetcher fetcher)
295 {
296 auto handler = [set = UnorderedSet<std::decay_t<decltype(*fetcher())>> {}](const auto &val) mutable { // NOLINT
297 if (set.count(val) == 0) {
298 set.insert(val);
299 return true;
300 }
301 return false;
302 };
303 return Filter(std::move(fetcher), std::move(handler));
304 }
305
306 template <typename Stream, std::enable_if_t<IsLazyStream<Stream>::value, int> = 0>
FirstElement(Stream stream)307 auto FirstElement(Stream stream)
308 {
309 return stream();
310 }
311
312 template <typename Stream, std::enable_if_t<IsLazyStream<Stream>::value, int> = 0>
IsLazyStreamEmpty(Stream stream)313 bool IsLazyStreamEmpty(Stream stream)
314 {
315 return !FirstElement(stream);
316 }
317
318 template <typename Stream, typename Pred, std::enable_if_t<IsLazyStream<Stream>::value, int> = 0>
Find(Stream stream,Pred pred)319 auto Find(Stream stream, Pred pred)
320 {
321 return FirstElement(Filter(stream, pred));
322 }
323
324 template <typename Stream, typename Pred, std::enable_if_t<IsLazyStream<Stream>::value, int> = 0>
IsPresent(Stream stream,Pred pred)325 bool IsPresent(Stream stream, Pred pred)
326 {
327 return Find(stream, pred);
328 }
329
330 template <typename LHS, typename RHS, std::enable_if_t<IsLazyStream<LHS>::value, int> = 0,
331 std::enable_if_t<IsLazyStream<RHS>::value, int> = 0>
JoinStreams(LHS lhs,RHS rhs)332 auto JoinStreams(LHS lhs, RHS rhs)
333 {
334 return [lhs, rhs]() mutable -> std::optional<std::tuple<decltype(*(lhs())), decltype(*(rhs()))>> {
335 auto lv = lhs();
336 if (!lv) {
337 return std::nullopt;
338 }
339 auto rv = rhs();
340 if (!rv) {
341 return std::nullopt;
342 }
343 return std::make_tuple(*lv, *rv);
344 };
345 }
346
347 template <typename LHS, typename MHS, typename RHS, std::enable_if_t<IsLazyStream<LHS>::value, int> = 0,
348 std::enable_if_t<IsLazyStream<MHS>::value, int> = 0, std::enable_if_t<IsLazyStream<RHS>::value, int> = 0>
JoinStreams(LHS lhs,MHS mhs,RHS rhs)349 auto JoinStreams(LHS lhs, MHS mhs, RHS rhs)
350 {
351 return [lhs, mhs, rhs]() mutable -> std::optional<std::tuple<std::remove_reference_t<decltype(*(lhs()))>,
352 std::remove_reference_t<decltype(*(mhs()))>,
353 std::remove_reference_t<decltype(*(rhs()))>>> {
354 auto lv = lhs();
355 if (!lv) {
356 return std::nullopt;
357 }
358 auto mv = mhs();
359 if (!mv) {
360 return std::nullopt;
361 }
362 auto rv = rhs();
363 if (!rv) {
364 return std::nullopt;
365 }
366 return std::make_tuple(*lv, *mv, *rv);
367 };
368 }
369 } // namespace panda::verifier
370
371 #endif // !_PANDA_LAZY_HPP
372