so true

心怀未来,开创未来!
随笔 - 160, 文章 - 0, 评论 - 40, 引用 - 0
数据加载中……

c++14 transducer

  1 /*
  2  * transducer.cpp
  3  *
  4  *  Created on: May 9, 2019
  5  *      Author: bacoo zhao
  6  *     Compile: g++ -g -Wall -std=c++14 transducer.cpp -o transducer
  7  *   Reference: http://vitiy.info/cpp14-how-to-implement-transducers/
  8  *              http://vitiy.info/templates-as-first-class-citizens-in-cpp11/
  9  *              http://vitiy.info/functional-pipeline-in-c11/
 10  */
 11 
 12 #include <functional>
 13 #include <type_traits>
 14 #include <utility>
 15 #include <vector>
 16 #include <string>
 17 #include <iostream>
 18 
 19 template<typename T>
 20 void print_type_trait() {
 21     std::cout << __PRETTY_FUNCTION__ << std::endl;
 22 }
 23 #define PRINT_TYPE_TRAIT(x) print_type_trait<decltype(x)>()
 24 
 25 namespace fn_detail {
 26 
 27 template<typename G, typename  Ts>
 28 struct tr_transducer {
 29     std::tuple<Tsparams;
 30 
 31     tr_transducer(Ts ts) :
 32             params(std::make_tuple(ts)) {
 33     }
 34 
 35     template<typename RF>
 36     auto operator()(RF&& step) const {
 37         return this->make(std::forward<RF>(step),
 38                 std::make_index_sequence<sizeof(Ts)>());
 39     }
 40 
 41     template<typename RF, std::size_tindexes_t>
 42     auto make(RF step, std::index_sequence<indexes_t>) const
 43     -> typename G::template apply<RF, Ts>
 44     {
 45         return {std::forward<RF>(step), std::get<indexes_t>(params)};
 46     }
 47 };
 48 
 49 template<typename  T>
 50 void noop(T  ts) {
 51 }
 52 
 53 struct tr_map_gen {
 54     template<typename ReducingFnT, typename MappingT>
 55     struct apply {
 56         ReducingFnT step;
 57         MappingT mapping;
 58 
 59         template<typename StateT, typename InputTs>
 60         bool operator()(StateT& out, InputTs&& ins) {
 61             return step(out, mapping(std::forward<decltype(ins)>(ins)));
 62         }
 63     };
 64 };
 65 
 66 struct tr_filter_gen {
 67     template<typename ReducingFnT, typename FilterT>
 68     struct apply {
 69         ReducingFnT step;
 70         FilterT pred;
 71 
 72         template<typename StateT, typename InputTs>
 73         bool operator()(StateT& out, InputTs&& ins) {
 74             if (pred(std::forward<decltype(ins)>(ins)))
 75                 return step(out, std::forward<decltype(ins)>(ins));
 76             else
 77                 return true;
 78         }
 79     };
 80 };
 81 
 82 struct tr_enumerate_gen {
 83     template<typename ReducingFnT, typename N>
 84     struct apply {
 85         ReducingFnT step;
 86         int n;
 87 
 88         template<typename StateT, typename InputTs>
 89         bool operator()(StateT& out, InputTs&& ins) {
 90             return step(out, n++, std::forward<decltype(ins)>(ins));
 91         }
 92     };
 93 };
 94 
 95 struct tr_limit_gen {
 96     template<typename ReducingFnT, typename N1, typename N2>
 97     struct apply {
 98         ReducingFnT step;
 99         int n;
100         int limit;
101 
102         template<typename StateT, typename InputTs>
103         bool operator()(StateT& out, InputTs&& ins) {
104             return (n++ > limit) ?
105                     false : step(out, std::forward<decltype(ins)>(ins));
106         }
107     };
108 };
109 
110 struct tr_each_gen {
111     template<typename ReducingFnT, typename EachFnT>
112     struct apply {
113         ReducingFnT step;
114         EachFnT each;
115 
116         template<typename StateT, typename InputTs>
117         bool operator()(StateT& out, InputTs&& ins) {
118             each(std::forward<decltype(ins)>(ins));
119             return true;
120         }
121     };
122 };
123 
124 } // end of namespace fn_detail
125 
126 template<typename T>
127 auto tr_map(T f) {
128     return fn_detail::tr_transducer<fn_detail::tr_map_gen, T>(f);
129 }
130 
131 template<typename T>
132 auto tr_filter(T pred) {
133     return fn_detail::tr_transducer<fn_detail::tr_filter_gen, T>(pred);
134 }
135 
136 auto tr_enumerate(int n = 0) {
137     return fn_detail::tr_transducer<fn_detail::tr_enumerate_gen, int>(n);
138 }
139 
140 auto tr_limit(int limit) {
141     return fn_detail::tr_transducer<fn_detail::tr_limit_gen, intint>(1, limit);
142 }
143 
144 template<typename T>
145 auto tr_each(T each) {
146     return fn_detail::tr_transducer<fn_detail::tr_each_gen, T>(each);
147 }
148 
149 /// The inversed chain of functors  is actually just a tuple of functors
150 template<typename  FNs>
151 class fn_chain_reversed {
152 private:
153     const std::tuple<FNs> functions;
154 
155     template<std::size_t I, typename Arg>
156     inline typename std::enable_if<I == sizeof(FNs) - 1, decltype(std::get<I>(functions)(std::declval<Arg>())) >::type
157     call(Arg arg) const
158     {
159         return std::get<I>(functions)(std::forward<Arg>(arg));
160     }
161 
162     template <std::size_t N, std::size_t I, typename Arg>
163     struct final_type : final_type<N-1, I+1, decltype(std::get<I>(functions)(std::declval<Arg>())) > {};
164 
165     template <std::size_t I, typename Arg>
166     struct final_type<0, I, Arg> {
167         using type = decltype(std::get<I>(functions)(std::declval<Arg>()));
168     };
169 
170     template <std::size_t I, typename Arg>
171     inline typename std::enable_if<I < sizeof(FNs) - 1, typename final_type<sizeof(FNs) - 1 - I, I, Arg>::type >::type
172     call(Arg arg) const
173     {
174         return this->call<I+1>(std::get<I>(functions)(std::forward<Arg>(arg)));
175     }
176 
177     static const bool isFunctionalChain = true;
178 
179 public:
180     fn_chain_reversed() : functions(std::tuple<>()) {}
181     fn_chain_reversed(std::tuple<FNs> functions) : functions(functions) {}
182 
183     // add function into chain (inversed order)
184     template< typename F >
185     inline auto add(const F& f) const -> fn_chain_reversed<F,FNs>
186     {
187         return fn_chain_reversed<F,FNs>(std::tuple_cat(std::make_tuple(f), functions));
188     }
189 
190     // call whole functional chain
191     template <typename Arg>
192     inline auto operator()(Arg arg) const -> decltype(this->call<0,Arg>(arg))
193     {
194         return call<0>(std::forward<Arg>(arg));
195     }
196 
197 };
198 
199 template<typename  FNs, typename F>
200 inline auto operator|(fn_chain_reversed<FNs> && transducer,
201         F&& rf) -> decltype(transducer.add(rf)) {
202     return transducer.add(std::forward<F>(rf));
203 }
204 
205 template<typename T, typename  FNs>
206 struct fn_isNotFunctionalChain {
207     static const bool value = true;
208 };
209 
210 template<>
211 struct fn_isNotFunctionalChain<fn_chain_reversed<> > {
212     static const bool value = false;
213 };
214 
215 template<typename T, class F, typename = std::enable_if_t<
216         fn_isNotFunctionalChain<F>::value> >
217 auto operator|(const F& f, T&& param) -> decltype(f(param)) {
218     return f(std::forward<T>(param));
219 }
220 
221 #define tr fn_chain_reversed<>()
222 
223 template<std::size_t Index, std::size_t Max>
224 struct tuple_all_neq_t {
225     template<typename Tuple1T, typename Tuple2T>
226     bool operator()(Tuple1T&& t1, Tuple2T&& t2) {
227         return std::get<Index>(std::forward<Tuple1T>(t1))
228                 != std::get<Index>(std::forward<Tuple2T>(t2))
229                 && tuple_all_neq_t<Index + 1, Max> { }(
230                         std::forward<Tuple1T>(t1), std::forward<Tuple2T>(t2));
231     }
232 };
233 
234 template<std::size_t Max>
235 struct tuple_all_neq_t<Max, Max> {
236     template<typename Tuple1T, typename Tuple2T>
237     bool operator()(Tuple1T&&, Tuple2T&&) {
238         return true;
239     }
240 };
241 
242 template<typename Tuple1T, typename Tuple2T>
243 bool tuple_all_neq(Tuple1T&& t1, Tuple2T&& t2) {
244     constexpr auto size1 = std::tuple_size<std::decay_t<Tuple1T> >::value;
245     constexpr auto size2 = std::tuple_size<std::decay_t<Tuple2T> >::value;
246 
247     using impl_t = tuple_all_neq_t<0u, (size1 > size2 ? size2 : size1)>;
248 
249     return impl_t { }(std::forward<Tuple1T>(t1), std::forward<Tuple2T>(t2));
250 }
251 
252 template<typename RF, typename A, std::size_t Indices, typename Ranges>
253 auto fn_accum_impl(std::index_sequence<Indices>, RF&& step, A& out,
254         Ranges  ranges) {
255     auto firsts = std::make_tuple(std::begin(ranges));
256     auto lasts = std::make_tuple(std::end(ranges));
257 
258     bool ok = true;
259     // just loop once
260     while (tuple_all_neq(firsts, lasts) && (ok)) {
261         ok = step(out, std::forward< decltype(*std::begin(ranges)) >(*std::get<Indices>(firsts)));
262         fn_detail::noop(++std::get<Indices>(firsts));
263     }
264 }
265 
266 template<typename T, typename RF, typename C, typename  Ins>
267 auto fn_tr_transduce(C init, T&& transducer, RF&& reducingFunction, Ins  ins) {
268     C out = init;
269     fn_accum_impl(std::make_index_sequence<sizeof(Ins)> {},
270             transducer(reducingFunction),
271             out,
272             (std::forward<Ins>(ins)));
273     return std::move(out);
274 }
275 
276 template<typename RF, typename C, typename  Ins>
277 auto fn_into_vector(RF step, C input, Ins  ins) {
278     return fn_tr_transduce(
279             std::vector<std::decay_t<decltype(*std::begin(input))>>(), step,
280             [] (auto& out, auto input) {
281                 out.push_back(input);
282                 return true;
283             }, std::forward<C>(input), (std::forward<Ins>(ins)));
284 }
285 
286 template<typename T, typename C, typename  Ins>
287 auto fn_tr_reduce(C&& init, T&& step, Ins  ins) {
288     C&& out = std::forward<C>(init);
289     fn_accum_impl(std::make_index_sequence<sizeof(Ins)> {},
290             std::forward<T>(step),
291             out,
292             (std::forward<Ins>(ins)));
293     return std::move(out);
294 }
295 
296 template<typename T, typename  Ins>
297 void fn_tr_end(T&& step, Ins  ins) {
298     auto step_wrap = step([](){});
299     int out = 0;
300     fn_accum_impl(std::make_index_sequence<sizeof(Ins)> {},
301             std::forward<decltype(step_wrap)>(step_wrap),
302             out,
303             (std::forward<Ins>(ins)));
304 }
305 
306 void my_func(int n, int x) {
307     std::cout << n << ":" << x << std::endl;
308 }
309 int main(int argc, char* argv[]) {
310     std::vector<int> input { 1, 2, 3, 4, 5, 6 };
311 
312     {
313         auto piping = tr | tr_map([](int x){return 2*x;}) | tr_filter([](int x){return x > 3 && x < 10;}) | tr_limit(2);
314         auto transducer = piping([](std::vector<int>& outint x) {
315             out.push_back(x);
316             return true;
317         });
318         //[with T =
319         //    fn_chain_reversed<
320         //        fn_detail::tr_transducer<fn_detail::tr_limit_gen, int, int>,
321         //        fn_detail::tr_transducer<fn_detail::tr_filter_gen, main(int, char**)::<lambda(int)> >,
322         //        fn_detail::tr_transducer<fn_detail::tr_map_gen, main(int, char**)::<lambda(int)> >
323         //    >
324         //]
325         PRINT_TYPE_TRAIT(piping);
326         //[with T =
327         //    fn_detail::tr_map_gen::apply<
328         //        fn_detail::tr_filter_gen::apply<
329         //            fn_detail::tr_limit_gen::apply<
330         //                main(int, char**)::<lambda(std::vector<int>&, int)>,
331         //                int,
332         //                int
333         //            >,
334         //            main(int, char**)::<lambda(int)>
335         //        >,
336         //        main(int, char**)::<lambda(int)>
337         //    >
338         //]
339         PRINT_TYPE_TRAIT(transducer);
340         auto result = fn_tr_reduce(std::vector<int>(), transducer, input);
341         // output:
342         // 4
343         // 6
344         for (auto x : result) {
345             std::cout << x << std::endl;
346         }
347     }
348 
349     std::cout << "============" << std::endl;
350 
351     {
352         auto result = fn_into_vector(tr |
353             tr_map([](int x){
354                 std::vector<int> v;
355                 for (int i = 1; i <= x; ++i) {
356                     v.push_back(i);
357                 }
358                 return v;
359             }) |
360             tr_map([](std::vector<int> v) {
361                 int sum = 0;
362                 for (auto x : v) {
363                     sum += x;
364                 }
365                 return sum;
366             }) |
367             tr_filter([](int x){
368                 return x > 4;
369             }), input);
370         // output:
371         // 6
372         // 10
373         // 15
374         // 21
375         for (auto x : result) {
376             std::cout << x << std::endl;
377         }
378     }
379 
380     std::cout << "============" << std::endl;
381 
382     {
383         std::vector<int> input2 { 4, 5, 6, 7 };
384         auto result = fn_into_vector(tr | tr_map([](int x, int y){ return x + y; }) | tr_filter([](int x){ return x > 5; }), input, input2);
385         // output:
386         // 7
387         // 9
388         // 11
389         for (auto x : result) {
390             std::cout << x << std::endl;
391         }
392     }
393 
394     std::cout << "============" << std::endl;
395 
396     {
397         auto enumerateStrings = (tr | tr_enumerate(1) | tr_limit(3) | tr_map([](int idx, std::string s) {
398                 char buf[1024];
399                 sprintf(buf, "elements[%d]=%s", idx, s.data());
400                 return std::string(buf);
401             }))([](std::vector<std::string>& out, std::string s) {
402                 out.push_back(s);
403                 return true;
404             });
405         auto result = fn_tr_reduce(std::vector<std::string>(), enumerateStrings, std::vector<std::string>{"a","b","c", "d"});
406         // output:
407         // elements[1]=a
408         // elements[2]=b
409         // elements[3]=c
410         for (auto x : result) {
411             std::cout << x << std::endl;
412         }
413     }
414 
415     std::cout << "============" << std::endl;
416 
417     {
418         // output:
419         // elements[1]=4
420         // elements[3]=6
421         // elements[5]=8
422         fn_tr_end(tr | tr_enumerate() | tr_filter([](int idx, int n){return idx % 2;}) |
423                 tr_limit(3) | tr_each([](int idx, int n){ std::cout << "elements[" << idx << "]=" << n << std::endl; }),
424             std::vector<int>{3, 4, 5, 6, 7, 8, 9});
425     }
426 
427     return 0;
428 }
429 

posted on 2019-05-09 18:53 so true 阅读(128) 评论(0)  编辑  收藏 所属分类: C&C++Linux


只有注册用户登录后才能发表评论。


网站导航: