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