Classdesc 3.44
function.h
Go to the documentation of this file.
1/*
2 @copyright Russell Standish 2000-2013
3 @author Russell Standish
4 This file is part of Classdesc
6 Open source licensed under the MIT license. See LICENSE for details.
7*/
8
9
13#ifndef CLASSDESC_FUNCTION_H
14#define CLASSDESC_FUNCTION_H
15#include "classdesc.h"
16#include <string>
17#include <utility>
18
19#if defined(__cplusplus) && __cplusplus>=201103L
20#include <array>
21#endif
22
23// given this is a header-only library, there shouldn't be an issue of
24// differing standards for name mangling between caller and callee
25#if defined(__GNUC__) && !defined(__ICC)
26#pragma GCC diagnostic push
27#pragma GCC diagnostic ignored "-Wnoexcept-type"
28#endif
29
30namespace classdesc
31{
32
33 /**
34 \namespace classdesc::functional \brief contains code generated by
35 functiondb.sh that defines functional attributes.
36 */
37 namespace functional
38 {
39
40 // these classes have either a const static member V, or a type T
42 //function object \a F
43 template <class F> struct Arity;
45 template <class F> struct Return;
46
48
49 /** \c Arg<F,i> is the type of argument \a i of \a F, i=1..Arity<F> */
50 template <class F, size_t> struct Arg;
51
53 template <class F> struct ClassOf
54 {typedef F T; typedef F type;};
55 template <class C, class U> struct ClassOf<U C::*>
56 {typedef C T; typedef C type;};
57
59 // note - this basically duplicates std::is_member_function_pointer
60 template <class F> struct is_member_function_ptr
61 {static const bool value=false;};
62
63 /// \c is_const_method::value is true if F is a pointer to a const method
64 template <class F> struct is_const_method
65 {static const bool value=false;};
66
68 template <class F> struct is_nonmember_function_ptr
69 {static const bool value=false;};
70 /// is_member_function_ptr<F>||is_nonmember_function_ptr<F>
71 /// note this is semantically different from std::is_function
72 template <class F> struct is_function
73 {
74 static const bool value=is_member_function_ptr<F>::value||
75 is_nonmember_function_ptr<F>::value;
76 };
80 template <class F, template<class> class Pred, int arity=Arity<F>::value> struct AllArgs;
83 template <class C, class M, class R=typename Return<M>::T, class Enable=void>
85
86 template <class O, class M>
87 bound_method<O,M> bindMethod(O& o, M m)
88 {return bound_method<O,M>(o,m);}
90
91 template <class T> struct Fdummy {Fdummy(int) {} };
92
95 apply function f to A arguments. Called from \c apply
96
97 Function definitions below left for documentation purposes, but
98 commented out to cause hard compilation failures when F is not
99 supported (eg has lvalue arguments)
101 template <class F, class Args> inline
102 typename Return<F>::T
103 apply_nonvoid_fn(F f, const Args& args, Fdummy<F> dum=0);
104
105 template <class F, class Args> inline
106 void apply_void_fn(F f, const Args& args, Fdummy<F> dum=0);
107 */
108
109#if defined(__cplusplus) && __cplusplus>=201103L
110 template <class A>
111 struct ArgAcceptable:
112 public And<
113 And<
114 And<is_default_constructible<typename remove_reference<A>::type>,
115 is_copy_constructible<typename remove_reference<A>::type>>,
116 And<
117 Not<std::is_rvalue_reference<A>>,
118 Or<Not<is_reference<A>>, is_const<typename remove_reference<A>::type>>
120 >,
121 Or<Not<is_pointer<A>>, is_same<A,const char*>>
122 >{};
123
124#endif
125
127 // USE_UNROLLED means use the functiondb.sh unrolled definitions instead of recursively expanded variadic templates
128#if defined(__cplusplus) && __cplusplus>=201103L && !defined(USE_UNROLLED)
129 template <class... Args> struct ArityArgs;
130
131 template <class A, class... Args>
132 struct ArityArgs<A, Args...>
134 static const size_t value=ArityArgs<Args...>::value+1;
135 };
137 template <>
138 struct ArityArgs<>
140 static const size_t value=0;
141 };
143 template <size_t N, class A, class... Args>
144 struct ArgOf
146 typedef typename ArgOf<N-1,Args...>::T T;
147 };
148
149 template <class A, class... Args>
150 struct ArgOf<1,A,Args...>
152 typedef A T;
153 };
155 template <template<class> class P, class... Args> struct AllArgsHelper;
156 template <template<class> class P, class A, class... Args> struct AllArgsHelper<P,A,Args...>
158 static const bool value=P<A>::value && AllArgsHelper<P,Args...>::value;
159 };
160
161 template <template<class> class P> struct AllArgsHelper<P>
163 static const bool value=true;
164 };
166 template <class R, class... Args> struct FunctionalHelper
167 {
168 static const size_t arity=ArityArgs<Args...>::value;
169 typedef R Return;
170 template <size_t N> struct Arg
172 typedef typename ArgOf<N,Args...>::T T;
173 };
174 template <template<class> class P> struct AllArgs
175 {
176 typedef AllArgsHelper<P,Args...> T;
177 };
178 };
180 /// argumentless specialisation
181 template <class R> struct FunctionalHelper<R>
182 {
183 static const size_t arity=0;
184 typedef R Return;
185 template <size_t N> struct Arg
187 typedef void T;
188 };
189 template <template<class> class P> struct AllArgs
190 {
191 typedef AllArgsHelper<P> T;
192 };
193 };
194
195 template <class F> struct FunctionalHelperFor;
196 // raw functions
197 template <class R, class... Args> struct FunctionalHelperFor<R(Args...)>
199 typedef FunctionalHelper<R,Args...> T;
200 };
201 // function pointers
202 template <class R, class... Args> struct FunctionalHelperFor<R(*)(Args...)>
203 {
204 typedef FunctionalHelper<R,Args...> T;
205 };
206 // method pointers
207 template <class R, class C, class... Args> struct FunctionalHelperFor<R(C::*)(Args...)>
208 {
209 typedef FunctionalHelper<R,Args...> T;
210 };
211 template <class R, class C, class... Args> struct FunctionalHelperFor<R(*C::*)(Args...)>
212 {
213 typedef FunctionalHelper<R,Args...> T;
214 };
215 template <class R, class C, class... Args> struct FunctionalHelperFor<R(C::*)(Args...) const>
217 typedef FunctionalHelper<R,Args...> T;
218 };
219#if defined(__cplusplus) && __cplusplus>=201703L
220 template <class R, class... Args> struct FunctionalHelperFor<R(Args...) noexcept>
222 typedef FunctionalHelper<R,Args...> T;
223 };
224 template <class R, class... Args> struct FunctionalHelperFor<R(*)(Args...) noexcept>
226 typedef FunctionalHelper<R,Args...> T;
227 };
228 template <class R, class C, class... Args> struct FunctionalHelperFor<R(C::*)(Args...) noexcept>
229 {
230 typedef FunctionalHelper<R,Args...> T;
231 };
232 template <class R, class C, class... Args> struct FunctionalHelperFor<R(C::*)(Args...) const noexcept>
234 typedef FunctionalHelper<R,Args...> T;
235 };
236#endif
237
237 /// member object pointers
238 template <class R, class C> struct FunctionalHelperFor<R(C::*)>
240 typedef FunctionalHelper<R> T;
241 };
243 template <class F> struct FunctionalHelperFor<std::function<F>>:
244 public FunctionalHelperFor<F> {};
246 // doesn't seem to work, alas...
247 // template <class F> struct FunctionalHelperFor:
248 // public FunctionalHelperFor<decltype(F::operator())> {};
249
252 // lambdas
253// template <class R, class... Args> struct FunctionalHelperFor<decltype([](Args...)->R)>
254// {
255// typedef typename FunctionalHelper<R,Args...>::T T;
256// };
257
258 template <class F> struct Arity {
259 typedef typename FunctionalHelperFor<F>::T Helper;
260 static const size_t V=Helper::arity;
261 static const size_t value=Helper::arity;
262 };
263
264 template <class F> struct Return
266 typedef typename FunctionalHelperFor<F>::T Helper;
267 typedef typename Helper::Return T;
268 typedef T type;
269 };
270 template <class F, size_t N> struct Arg
272 typedef typename FunctionalHelperFor<F>::T Helper;
273 typedef typename Helper::template Arg<N>::T T;
274 typedef T type;
275 };
277 template <class R, class C, class... Args>
278 struct ClassOf<R (C::*)(Args...)>
279 {
280 typedef C T;
281 typedef C type;
282 };
284 template <class R, class C, class... Args>
285 struct ClassOf<R (*C::*)(Args...)>
287 typedef C T;
288 typedef C type;
289 };
291 template <class R, class C, class... Args>
292 struct ClassOf<R (C::*)(Args...) const>
293 {
294 typedef C T;
295 typedef C type;
296 };
298 template <class C, class R, class... Args>
299 struct is_member_function_ptr<R (C::*)(Args...)>
300 {
301 static const bool value=true;
302 };
304 template <class C, class R, class... Args>
305 struct is_member_function_ptr<R (C::*)(Args...) const>
306 {
307 static const bool value=true;
308 };
310 template <class C, class R, class... Args>
311 struct is_const_method<R (C::*)(Args...) const>
313 static const bool value=true;
314 };
316 template <class R, class... Args>
317 struct is_nonmember_function_ptr<R (*)(Args...)>
319 static const bool value=true;
320 };
322 template <class C, class R, class... Args>
323 struct is_nonmember_function_ptr<R (*C::*)(Args...)>
324 {
325 static const bool value=true;
326 };
328 // true if C is non const, or M is a const member function or static
329 template <class C, class M>
330 struct ConstCorrect: public
331 Or< Not<is_const<C>>,
332 Or<is_pointer<M>, is_const_method<M>>> {};
334 template <class C, class M, class R>
335 class bound_method<C,M,R,
336 typename enable_if<
337 And<ConstCorrect<C,M>, AllArgs<M,ArgAcceptable>>,
338 void>::T>
340 C* obj;
341 M method;
342 public:
343 bound_method(C& obj, M method): obj(&obj), method(method) {}
344 template <class... Args>
345 R operator()(Args... args) const {return (obj->*method)(args...);}
346 void rebind(C& newObj) {obj=&newObj;}
347 static const bool is_const=is_const_method<M>::value;
348 };
349
350 template <class C, class M, class R>
351 class bound_method<C,M,R,
352 typename enable_if<
353 Not<And<ConstCorrect<C,M>, AllArgs<M,ArgAcceptable>>>,
354 void>::T>
356 C* obj;
357 M method;
358 public:
359 bound_method(C& obj, M method): obj(&obj), method(method) {}
360 template <class... Args>
361 R operator()(Args... args) const
363 // can't call, argument unacceptable
364 throw std::runtime_error("cannot call method, inappropriate argument type");
365 }
366 void rebind(C& newObj) {obj=&newObj;}
367 static const bool is_const=is_const_method<M>::value;
368 };
370 template <class C, class M>
371 class bound_method<C, M, void,
372 typename enable_if<
373 And<ConstCorrect<C,M>, AllArgs<M,ArgAcceptable>>,
374 void>::T>
375 {
376 C* obj;
377 M method;
378 public:
379 bound_method(C& obj, M method): obj(&obj), method(method) {}
380 template <class... Args>
381 void operator()(Args... args) const {(obj->*method)(args...);}
382 void rebind(C& newObj) {obj=&newObj;}
383 static const bool is_const=is_const_method<M>::value;
384 };
386 template <class C, class F> struct FunctionalHelperFor<bound_method<C,F>>
387 {
388 typedef typename FunctionalHelperFor<F>::T T;
389 };
391 template <class F, template<class> class P, int N> /*N not actually used anywhere...*/
392 struct AllArgs
393 {
394 typedef typename FunctionalHelperFor<F>::T Helper;
395 typedef typename Helper::template AllArgs<P>::T AllArgsHelper;
396 static const bool value=AllArgsHelper::value;
397 };
398
399 template <class F, class ArgVector, size_t N=Arity<F>::value>
400 struct CurryLastNonVoid;
402 template <class F, class ArgVector, size_t N>
403 struct CurryLastNonVoid
404 {
405 F f;
407 CurryLastNonVoid(F f, ArgVector& a): f(f), a(a) {}
408 template <class... Args>
409 typename Return<F>::T operator()(Args... args) const {
410 return f(args...,a[Arity<F>::value-1]);
411 }
412
413 typename Return<F>::T apply()
414 {return CurryLastNonVoid<CurryLastNonVoid, ArgVector>(*this, a).apply();}
415 };
416
417 template <class F, class ArgVector>
418 struct CurryLastNonVoid<F,ArgVector,0>
419 {
420 F f;
422 CurryLastNonVoid(F f, ArgVector& a): f(f), a(a) {}
423 typename Return<F>::T operator()() const {return f();}
424 typename Return<F>::T apply() const {return f();}
425 };
427 template <class F, class ArgVector,size_t N>
428 struct Return<CurryLastNonVoid<F,ArgVector,N>>
430 typedef typename Return<F>::T T;
431 };
432
433 template <class F, class ArgVector, size_t N>
434 struct Arity<CurryLastNonVoid<F,ArgVector,N>>
436 static const size_t value=Arity<F>::value-1;
437 };
438
439 template <class F, class ArgVector, size_t N=Arity<F>::value>
440 struct CurryLastVoid
442 F f;
444 CurryLastVoid(F f, ArgVector& a): f(f), a(a) {}
445 template <class... Args>
446 void operator()(Args... args) const {
447 f(args...,a[Arity<F>::value-1]);
448 }
449
450 void apply()
451 {CurryLastVoid<CurryLastVoid, ArgVector>(*this, a).apply();}
452 };
454 template <class F, class ArgVector>
455 struct CurryLastVoid<F,ArgVector,0>
456 {
457 F f;
458 ArgVector& a;
459 CurryLastVoid(F f, ArgVector& a): f(f), a(a) {}
460 void operator()() const {f();}
461 void apply() const {f();}
462 };
463
464 template <class F, class ArgVector>
465 struct Arity<CurryLastVoid<F,ArgVector>>
467 static const size_t value=Arity<F>::value-1;
468 };
469
470 template <class F, class Args>
472 apply_nonvoid_fn(F f, Args& a)
474 return CurryLastNonVoid<F,Args>(f,a).apply();
475 }
476
477
478 template <class F, class Args>
480 apply_void_fn(F f, Args& a)
481 {
482 CurryLastVoid<F,Args>(f,a).apply();
483 }
484
485
485 /**
486 helper classes to serialise/deserialise a function call to
487 assist with command patterns
489 Use like
490 pack_t buf;
491 PackFunctor(buf)(a, b);
492 ...
493 Functor object;
494 UnpackAndCall(buf)(object);
495
497 template <class F, class R=typename Return<F>::T,
498 class A=typename Arg<F,1>::T>
499 class CurryFirst;
500
501 template <class F, class R, class A, size_t I>
502 struct Arg<CurryFirst<F,R,A>,I>
504 typedef typename Arg<F,I+1>::T T;
505 typedef T type;
506 };
507
508 template <class F, class R, class A>
509 struct Return<CurryFirst<F,R,A> >
511 typedef R T;
512 typedef T type;
513 };
515 template <class F, class R, class A>
516 struct Arity<CurryFirst<F,R,A> >
518 const int V=Arity<F>::V-1;
519 const int value=V;
520 };
521
523 template <class F, class R, class A>
524 class CurryFirst
525 {
526 F f;
527 A& a;
528 public:
529 CurryFirst(F f, A& a): f(f), a(a) {}
530 template <class... Args>
531 R operator()(Args... args) {
532 return f(std::forward<A>(a),std::forward<Args>(args)...);
534 };
536 template <class F, class A>
537 class CurryFirst<F,void,A>
539 F f;
540 A& a;
541 public:
542 CurryFirst(F f, A& a): f(f), a(a) {}
543 template <class... Args>
544 void operator()(Args... args) {
545 f(std::forward<A>(a),std::forward<Args>(args)...);
546 }
547 };
548
549 template <class F, class R, class A>
550 struct FunctionalHelperFor<CurryFirst<F,R,A>>:
551 public FunctionalHelperFor<F>
553 template <size_t N> struct Arg: public functional::Arg<F,N+1> {};
554 };
555
556 template <class Buffer, class F, class R=typename Return<F>::T,
557 int N=Arity<F>::value> class CallOnBuffer;
559 /// extract an argument from buffer \a b, and run functional f on it
560 template <class F, class A, class R, class B>
562 eval(F f, B& b)
563 {
564 A a{};
565 b>>a;
566 return f(a);
569 template <class F, class A, class R, class B>
570 typename enable_if<And<ArgAcceptable<A>,is_same<A,const char*>>, R>::T
571 eval(F f, B& b)
572 {
573 std::string a{};
574 b>>a;
575 const char* tmp=a.c_str();
576 return f(tmp);
578
579 template <class F, class A, class R, class B>
581 eval(F f, B& b)
583 throw std::runtime_error("unable to unpack into "+typeName<A>());
586 template <class Buffer, class F, class R, int N>
587 class CallOnBuffer
588 {
589 Buffer& buffer;
590 F f;
591 typedef typename remove_const
592 <typename remove_reference
593 <typename Arg<F,1>::T>::type>::type A1;
594 public:
595 CallOnBuffer(Buffer& buffer, F f): buffer(buffer), f(f) {}
596 R operator()() {
597 auto ff=[&](typename Arg<F,1>::T a)->R {return CallOnBuffer<Buffer, CurryFirst<F>, R, N-1>
598 (buffer, CurryFirst<F>(f,a))();};
599 return eval<decltype(ff),A1,R,Buffer>(ff, buffer);
600 }
601 };
603 template <class Buffer, class F, class R>
604 class CallOnBuffer<Buffer,F,R,0>
606 F f;
607 public:
608 CallOnBuffer(Buffer& buffer, F f): f(f) {}
609 R operator()() {return f();}
610 };
612 template <class Buffer, class F>
613 typename Return<F>::T callOnBuffer(Buffer& buff, F f)
614 {return CallOnBuffer<Buffer,F,typename Return<F>::T>(buff,f)();}
615
616
617 template <class Buffer>
618 class PackFunctor: public Buffer
620 public:
621 /// a Buffer needs to support << operations for arbitrary rhs types
622 template <class... Args> PackFunctor(Args... args):
623 Buffer(std::forward<Args>(args)...) {}
624
625 template <class F, class... Args>
626 void pack(Args... args)
627 {packArg<F,1>(args...);}
629 template <class... Args>
630 void pack(Args... args)
631 {packArg<void(Args...),1>(args...);}
632 template <class F, int N, class A, class... Args>
633 void packArg(A a, Args... args)
634 {
635 (*this) << typename Arg<F,N>::T(a);
636 packArg<F,N+1>(args...);
637 }
638 template <class F, int N>
639 void packArg() {}
641 template <class F>
642 typename Return<F>::T call(F f) {
643 return CallOnBuffer<Buffer, F>(*this,f)();
644 }
645 };
647#else
651 template <class R, class C> struct Return<R (C::*)>
652 {typedef R T; typedef R type;};
653
654 template <class C, class M>
655 struct Arity<bound_method<C,M> >
657 static const int V=Arity<M>::V;
658 static const int value=V;
659 };
660
661 template <class C, class M>
662 struct Return<bound_method<C,M> >
664 typedef typename Return<M>::T T;
665 typedef T type;
666 };
668 template <class C, class M, size_t i>
669 struct Arg<bound_method<C,M>,i>
671 typedef typename Arg<M,i>::T T;
672 typedef T type;
673 };
674
675#if defined(__GNUC__) && !defined(__ICC)
676#pragma GCC diagnostic push
677#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
678#endif
679#include "functiondb.h"
680#if defined(__GNUC__) && !defined(__ICC)
681#pragma GCC diagnostic pop
682#endif
683
684 template <class Buffer>
685 struct PackFunctor: public Buffer
687 PackFunctor() {}
688 PackFunctor(const Buffer& buffer): Buffer(buffer) {}
689
690 // TODO other C++11 stuff?
691 template <class F>
692 typename Return<F>::T call(F f) {return callOnBuffer(*this, f);}
693 };
694
695
696#endif
697
698 template <class F, class Args>
699 typename enable_if<
701 void
702 >::T
703 apply(typename Return<F>::T* r, F f, const Args& args, dummy<0> d=0)
704 {*r=apply_nonvoid_fn(f,args);}
706 template <class F, class Args>
708 apply(void* r, F f, Args& args, dummy<1> d=0)
709 {apply_void_fn(f,args);}
710 }
712#ifdef CLASSDESC_
713#pragma omit typeName functional::bound_method<C,M,R,E>
714#endif
715
716 template <class C, class M, class R, class E>
717 struct tn<functional::bound_method<C,M,R,E> >
718 {
719 static string name() {return "classdesc::bound_method<"+typeName<C>()+","+typeName<M>()+">";}
720 };
722}
724#if defined(__GNUC__) && !defined(__ICC)
725#pragma GCC diagnostic pop
726#endif
727
728#endif
Definition javaClass_base.h:249
Definition function.h:84
contains code generated by functiondb.sh that defines functional attributes.
Contains definitions related to classdesc functionality.
void pack(pack_t &targ, const string &desc, is_treenode dum, const T *const &arg)
serialise a tree (or DAG)
Definition pack_graph.h:28
STL namespace.
Definition classdesc.h:420
Definition RESTProcess_epilogue.h:159
Definition classdesc.h:405
Definition classdesc.h:423
Definition classdesc.h:299
controlled template specialisation: stolen from boost::enable_if.
Definition classdesc.h:282
Definition function.h:80
Definition function.h:50
Arity::V (or ::value) is the number of arguments of
Definition function.h:43
Definition function.h:54
Definition function.h:686
Return::T (or ::type) is the return type of F
Definition function.h:45
is_const_method::value is true if F is a pointer to a const method
Definition function.h:65
Definition function.h:73
is_member_function_ptr::value is true if F is a member function pointer
Definition function.h:61
is_nonmember_function_ptr::value is true if F is an ordinary function pointer (maybe a member)
Definition function.h:69
Definition classdesc.h:571