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