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