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