• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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