Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
feed-manifold.hpp
Go to the documentation of this file.
1/*
2 FEED-MANIFOLD.hpp - data feed connection system for render nodes
3
4 Copyright (C)
5 2008, Hermann Vosseler <Ichthyostega@web.de>
6 2023, Hermann Vosseler <Ichthyostega@web.de>
7
8  **Lumiera** is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by the
10  Free Software Foundation; either version 2 of the License, or (at your
11  option) any later version. See the file COPYING for further details.
12
13*/
14
15
72#ifndef ENGINE_FEED_MANIFOLD_H
73#define ENGINE_FEED_MANIFOLD_H
74
75
76#include "lib/error.hpp"
77#include "lib/nocopy.hpp"
80#include "lib/meta/function.hpp"
81#include "lib/meta/trait.hpp"
87
88
89namespace steam {
90namespace engine {
91
92 namespace {// Introspection helpers....
93
94 using lib::meta::_Fun;
102 using lib::meta::Tagged;
103 using lib::meta::Types;
104 using lib::meta::Nil;
105 using std::is_pointer;
106 using std::is_reference;
107 using std::is_convertible;
108 using std::is_constructible;
109 using std::is_copy_constructible;
110 using std::remove_pointer_t;
111 using std::tuple_element_t;
112 using std::add_pointer_t;
113 using std::conditional_t;
114 using std::__and_;
115 using std::__not_;
116
117
118 template<typename V>
119 struct is_Value
120 : __and_<__not_<is_pointer<V>>
121 ,__not_<is_reference<V>>
122 ,std::is_default_constructible<V>
123 ,std::is_copy_assignable<V>
124 >
125 { };
126
127 template<typename B>
129 : __and_<is_pointer<B>
130 ,__not_<_Fun<B>>
131 ,std::is_default_constructible<remove_pointer_t<B>>
132 >
133 { };
134
135
136
137
153 template<class FUN>
154 struct _ProcFun
155 {
156 static_assert(_Fun<FUN>() , "something funktion-like required");
157 static_assert(0 < _Fun<FUN>::ARITY , "function with at least one argument expected");
158 static_assert(3 >= _Fun<FUN>::ARITY , "function with up to three arguments accepted");
159
161
162 template<size_t i>
164
165 template<size_t i, template<class> class COND>
166 using AllElements = ElmTypes<_Arg<i>>::template AndAll<COND>;
167
168 template<size_t i>
169 static constexpr bool nonEmpty = ElmTypes<_Arg<i>>::SIZ;
170 template<size_t i>
171 static constexpr bool is_BuffSlot = AllElements<i, is_Buffer>();
172 template<size_t i>
173 static constexpr bool is_ParamSlot = AllElements<i, is_Value>();
174
178 template<class SIG, typename SEL =void>
179 struct _Case
180 {
181 static_assert (not sizeof(SIG), "use case could not be determined from function signature");
182 };
183 template<class SIG>
184 struct _Case<SIG, enable_if<is_UnaryFun<SIG>>>
185 {
186 enum{ SLOT_O = 0
187 , SLOT_I = 0
188 };
189 };
190 template<class SIG>
191 struct _Case<SIG, enable_if<is_BinaryFun<SIG>>>
192 {
193 enum{ SLOT_O = 1
194 , SLOT_I = (nonEmpty<0> and is_BuffSlot<0>)? 0 : 1
195 };
196 };
197 template<class SIG>
198 struct _Case<SIG, enable_if<is_TernaryFun<SIG>>>
199 {
200 enum{ SLOT_O = 2
201 , SLOT_I = 1
202 };
203 };
204
207 using SigP = _Arg< 0>;
211
212 // Metaprogramming helper for Buffer types (sans pointer)
213 using ElmsI = ElmTypes<typename ElmTypes<SigI>::template Apply<remove_pointer_t>>;
214 using ElmsO = ElmTypes<typename ElmTypes<SigO>::template Apply<remove_pointer_t>>;
215
216 enum{ FAN_I = ElmTypes<SigI>::SIZ
221 , SLOT_P = 0
222 };
223
224 static constexpr bool hasInput() { return SLOT_I != SLOT_O; }
225 static constexpr bool hasParam() { return 0 < SLOT_I; }
226
227 /* ========== |consistency checks| ========== */
228 static_assert (nonEmpty<SLOT_O> or nonEmpty<SLOT_I> or nonEmpty<SLOT_P>
229 ,"At least one slot of the function must accept data");
230 static_assert (is_BuffSlot<SLOT_O>, "Output slot of the function must accept buffer pointers");
231 static_assert (is_BuffSlot<SLOT_I>, "Input slot of the function must accept buffer pointers");
232 static_assert (is_ParamSlot<SLOT_P> or not hasParam()
233 ,"Param slot must accept value data");
234 };
235
236
245 template<class FUN>
247 {
249
250 static constexpr bool hasParam() { return _Proc::hasParam(); }
251
252 using Param = conditional_t<hasParam(), typename _Proc::SigP, std::tuple<>>;
253
254 template<class PF>
256 template<class PF>
257 using SigP = add_pointer_t<typename _Fun<PF>::Sig>;
258
259 template<class PF>
260 using isSuitable = is_constructible<Param, Res<PF>>;
261 template<class PF>
262 using canInvoke = std::is_invocable<PF, TurnoutSystem&>;
263
264 template<class PF>
265 using isConfigurable = __and_<is_constructible<bool, PF&>
266 ,__not_<is_convertible<PF&, SigP<PF>>>
267 >; // non-capture-λ are convertible via function-ptr to bool
268 // yet we want to detect a real built-in bool-conversion.
269 template<class PF>
270 static bool
271 isActivated (PF const& paramFun)
272 {
273 if constexpr (isSuitable<PF>())
274 { if constexpr (isConfigurable<PF>())
275 return bool(paramFun);
276 else
277 return true;
278 }
279 return false;
280 }
281
282
283 template<class PF>
284 static constexpr bool canAdapt() { return isSuitable<PF>(); }
285 template<class PF>
286 static constexpr bool isParamFun() { return isSuitable<PF>() and canInvoke<PF>(); }
287 template<class PF>
288 static constexpr bool canActivate() { return isSuitable<PF>() and isConfigurable<PF>(); }
289 };
290
293 {
294 void operator() (void) const {/*I do make a difference, I really do!*/}
295 };
296
297 }//(End)Introspection helpers.
298
299
300
301 template<class FUN, class PAM =_Disabled>
302 class FeedPrototype;
303
304
317 template<class FUN>
319 {
320 using _Trait = _ProcFun<FUN>;
321
322 static constexpr bool hasInput() { return _Trait::hasInput(); }
323 static constexpr bool hasParam() { return _Trait::hasParam(); }
324
325 enum{ FAN_P = hasParam()? _Trait::FAN_P : 0
326 , FAN_I = hasInput()? _Trait::FAN_I : 0
327 , FAN_O = _Trait::FAN_O
328 };
329
330 template<size_t fan>
332 // ^^^ can not be default-constructed
335
336 using Param = conditional_t<hasParam(), typename _Trait::SigP, std::tuple<>>;
337 using ArgI = conditional_t<hasInput(), typename _Trait::SigI, std::tuple<>>;
338 using ArgO = _Trait::SigO;
339
340
343 {
345
347 : param{}
348 { }
349
350 template<typename...INIT>
351 ParamStorage (INIT&& ...paramInit)
352 : param{forward<INIT> (paramInit)...}
353 { }
354 };
355
362
369
370 template<typename F>
372
373 template<class X>
374 using NotProvided = Tagged<Nil, X>;
375
376 template<bool yes, class B>
377 using Provide_if = conditional_t<yes, B, NotProvided<B>>;
378
382
388 struct Storage
390 , FeedOutput
391 , FeedInput
392 , FeedParam
393 {
395
396 template<typename F>
397 Storage (F&& fun)
398 : process{forward<F> (fun)}
399 { }
400
401 template<typename F, typename =enable_if_hasParam<F>>
402 Storage (Param p, F&& fun)
403 : FeedParam{move (p)}
404 , process{forward<F> (fun)}
405 { }
406 };
407 };
408
409
442 template<class FUN>
444 : _StorageSetup<FUN>::Storage
445 {
446 using _T = _ProcFun<FUN>;
449
452
453 using ArgI = _S::ArgI;
454 using ArgO = _S::ArgO;
456 enum{ FAN_I = _S::FAN_I
459 };
460
461 static constexpr bool hasInput() { return _S::hasInput(); }
462 static constexpr bool hasParam() { return _S::hasParam(); }
463
464
470
471
472
473 template<size_t i, class ARG>
474 auto&
475 accessArg (ARG& arg)
476 {
477 if constexpr (tuple_like<ARG>)
478 return lib::meta::getElm<i> (arg);
479 else
480 return arg;
481 }
482
483 using TupI = _T::ElmsI::Tup;
484 using TupO = _T::ElmsO::Tup;
485
486
487 void
489 {
490 if constexpr (hasInput())
491 {
492 forEachIDX<TupI> ([&](auto i)
493 {
494 using BuffI = tuple_element_t<i, TupI>;
495 accessArg<i> (_F::inArgs) = & _F::inBuff[i].template accessAs<BuffI>();
496 });
497 }
498 // always wire output buffer(s)
499 {
500 forEachIDX<TupO> ([&](auto i)
501 {
502 using BuffO = tuple_element_t<i, TupO>;
503 accessArg<i> (_F::outArgs) = & _F::outBuff[i].template accessAs<BuffO>();
504 });
505 }
506 }
507
508 void
510 {
511 if constexpr (hasParam())
512 if constexpr (hasInput())
513 _F::process (_F::param, _F::inArgs, _F::outArgs);
514 else
515 _F::process (_F::param, _F::outArgs);
516 else
517 if constexpr (hasInput())
518 _F::process (_F::inArgs, _F::outArgs);
519 else
521 }
522 };
523
524
525
547 template<class FUN, class PAM>
550 {
551 using _Proc = _ProcFun<FUN>;
552 using _Trait = _ParamFun<FUN>;
553
556
557 public:
559 enum{ FAN_I = Feed::FAN_I
560 , FAN_O = Feed::FAN_O
561 , FAN_P = Feed::FAN_P
562 };
563 using ElmsI = _Proc::ElmsI;
564 using ElmsO = _Proc::ElmsO;
565 using ElmsP = conditional_t<_Trait::hasParam(), typename _Proc::ArgP, Types<>>;
566 using Param = _Proc::SigP;
567
568 template<template<class> class META>
569 using OutTypesApply = ElmsO::template Apply<META>;
570
571
573 FeedPrototype (FUN&& proc)
574 : procFun_{move (proc)}
575 , paramFun_{}
576 { }
577
578 FeedPrototype (FUN&& proc, PAM&& par)
579 : procFun_{move (proc)}
580 , paramFun_{move (par)}
581 { }
582 // default move acceptable : pass pre-established setup
583
584 static constexpr bool hasParam() { return _Trait::hasParam(); }
585 static constexpr bool hasParamFun() { return _Trait::template isParamFun<PAM>(); }
586 static constexpr bool canActivate() { return _Trait::template canActivate<PAM>(); }
587
589 bool isActivated() const { return _Trait::isActivated(paramFun_); }
590
591
592
593 /************************************************************/
596 Feed
598 {
599 if constexpr (hasParamFun())
600 if (isActivated())
601 return Feed(paramFun_(turnoutSys), procFun_);
602 return Feed{procFun_};
603 }
604
605
606
607 /* ======= cross-builder API ======= */
608
609 using ProcFun = FUN;
610 using ParamFun = PAM;
611
612 template<typename PFX>
614
616 template<typename PFX>
617 static constexpr bool isSuitableParamFun()
618 {
619 return hasParam() and _Trait::template isParamFun<PFX>();
620 }
623 template<typename PFX>
624 static constexpr bool isSuitableParamAdaptor()
625 {
626 return hasParam() and _Trait::template canAdapt<PFX>();
627 }
628
638 template<typename PFX>
639 auto
640 moveAdaptedParam (PFX otherParamFun =PFX{})
641 {
642 using OtherParamFun = std::decay_t<PFX>;
643 return Adapted<OtherParamFun>{move(procFun_), move(otherParamFun)};
644 }
645
646
650 enable_if<__and_<is_copy_constructible<FUN>
651 ,is_copy_constructible<PAM>>, FeedPrototype>
652 clone() const
653 {
654 return FeedPrototype{FUN(procFun_), PAM(paramFun_)};
655 }
656
664 template<typename PFX =PAM, typename = enable_if<std::is_assignable<PAM,PFX>>>
666 assignParamFun (PFX&& paramFunDef =PAM{})
667 {
668 paramFun_ = forward<PFX> (paramFunDef);
669 return move(*this);
670 }
671
672
675 template<typename TRA>
676 auto
677 decorateProcParam (TRA paramTransformer)
678 {
679 static_assert (_Trait::hasParam(), "Processing-functor with parameters expected");
680 static_assert (isSuitableParamAdaptor<TRA>(), "Given functor's output not suitable "
681 "for adapting the proc-functor's 1st argument");
682 using SigP = lib::meta::_FunArg<TRA>;
683 using SigI = _Proc::SigI;
684 using SigO = _Proc::SigO;
685 if constexpr (_Proc::hasInput())
686 {
687 return [procFun = move(procFun_)
688 ,transform = move(paramTransformer)
689 ]
690 (SigP par, SigI in, SigO out)
691 {
692 return procFun (transform(par), in, out);
693 };
694 }
695 else
696 {
697 return [procFun = move(procFun_)
698 ,transform = move(paramTransformer)
699 ]
700 (SigP par, SigO out)
701 {
702 return procFun (transform(par), out);
703 };
704 }
705 }
706
707 template<typename TRA>
708 using DecoratedProcFun = decltype(std::declval<FeedPrototype>().decorateProcParam (std::declval<TRA>()));
709
710 template<typename TRA>
712
719 template<typename TRA>
720 auto
721 moveTransformedParam (TRA paramTransformer)
722 {
723 return Decorated<TRA>{decorateProcParam (move(paramTransformer)), move(paramFun_)};
724 }
725
726 };
727
728}} // namespace steam::engine
729#endif /*ENGINE_FEED_MANIFOLD_H*/
A front-end to support the buffer management within the render nodes.
Block of raw uninitialised storage with array like access.
Builder-Prototype to create FeedManifold instances.
static constexpr bool canActivate()
FeedPrototype(FUN &&proc, PAM &&par)
FeedPrototype< DecoratedProcFun< TRA >, PAM > Decorated
Feed buildFeed(TurnoutSystem &turnoutSys)
create suitable Feed(Manifold) for processing a Node invocation
auto decorateProcParam(TRA paramTransformer)
static constexpr bool hasParamFun()
auto moveTransformedParam(TRA paramTransformer)
Adapt parameter handling of the processing-function by passing parameters through an adapter functor ...
static constexpr bool isSuitableParamFun()
is the given functor suitable as parameter functor for this Feed?
FeedPrototype< FUN, PFX > Adapted
ElmsO::template Apply< META > OutTypesApply
static constexpr bool hasParam()
FeedPrototype(FUN &&proc)
setup with processing-functor only
static constexpr bool isSuitableParamAdaptor()
is the given functor suitable to adapt the parameter argument of the processing-functor to accept dif...
auto moveAdaptedParam(PFX otherParamFun=PFX{})
Cross-Builder to add configuration with a given parameter-functor.
FeedPrototype && assignParamFun(PFX &&paramFunDef=PAM{})
Change the current parameter-functor setup by assigning some value.
decltype(std::declval< FeedPrototype >().decorateProcParam(std::declval< TRA >())) DecoratedProcFun
enable_if< __and_< is_copy_constructible< FUN >, is_copy_constructible< PAM > >, FeedPrototype > clone() const
build a clone-copy of this prototype, holding the same functors
conditional_t< _Trait::hasParam(), typename _Proc::ArgP, Types<> > ElmsP
Communication hub to coordinate and activate the »Render Node Network« performance.
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
Any copy and copy construction prohibited.
Definition nocopy.hpp:38
Concept to mark any type compliant to the »tuple protocol«
Lumiera error handling (C++ interface).
Metaprogramming tools for detecting and transforming function types.
Helpers for working with lib::meta::Types (i.e.
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
void forEachIDX(FUN &&fun)
Invoke a function (or λ) with index numbers derived from some variadic count.
has_Arity< FUN, 1 > is_UnaryFun
Definition function.hpp:280
has_Arity< FUN, 3 > is_TernaryFun
Definition function.hpp:286
has_Arity< FUN, 2 > is_BinaryFun
Definition function.hpp:283
»Empty« mark
Definition typelist.hpp:82
variadic sequence of types
Definition typelist.hpp:102
Steam-Layer implementation namespace root.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
#define Type(_EXPR_)
Variadic type sequence builder.
Trait template for uniform access to function signature types.
Definition function.hpp:144
Adapter to connect input/output buffers to a processing functor backed by an external library.
static constexpr bool hasInput()
FeedPrototype< FUN > Prototype
cross-builder: Prototype can be used to attach parameter-provider-functors and then to create several...
static constexpr bool hasParam()
FeedManifold building block: hold output buffer pointers.
FeedManifold building block: hold parameter data.
Data Storage block for the FeedManifold Flexibly configured based on the processing function.
Configuration context for a FeedManifold.
static constexpr bool hasInput()
conditional_t< yes, B, NotProvided< B > > Provide_if
Provide_if< hasParam(), ParamStorage > FeedParam
conditional_t< hasParam(), typename _Trait::SigP, std::tuple<> > Param
Provide_if< hasInput(), BufferSlot_Input > FeedInput
lib::meta::enable_if_c< _ProcFun< F >::hasParam()>::type enable_if_hasParam
static constexpr bool hasParam()
conditional_t< hasInput(), typename _Trait::SigI, std::tuple<> > ArgI
FeedManifold building block: hold input buffer pointers.
Trait template to handle an associated parameter functor.
conditional_t< hasParam(), typename _Proc::SigP, std::tuple<> > Param
__and_< is_constructible< bool, PF & >,__not_< is_convertible< PF &, SigP< PF > > > > isConfigurable
Trait template to analyse and adapt to the given processing function.
ElmTypes< typename ElmTypes< SigI >::template Apply< remove_pointer_t > > ElmsI
ElmTypes< _Arg< i > >::template AndAll< COND > AllElements
ElmTypes< typename ElmTypes< SigO >::template Apply< remove_pointer_t > > ElmsO
Detect use-case as indicated by the function signature.
A collection of frequently used helper functions to support unit testing.
Helpers for type detection, type rewriting and metaprogramming.
Metaprogramming with tuples-of-types and the std::tuple record.
Some basic facilities for manipulating type sequences.
A raw memory block with proper alignment and array access.
Metaprogramming with type sequences based on variadic template parameters.