Lumiera  0.pre.03
»edit your freedom«
weaving-pattern-builder.hpp
Go to the documentation of this file.
1 /*
2  WEAVING-PATTERN-BUILDER.hpp - build an invocation pattern for media calculations
3 
4  Copyright (C)
5  2024, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
90 #ifndef STEAM_ENGINE_WEAVING_PATTERN_BUILDER_H
91 #define STEAM_ENGINE_WEAVING_PATTERN_BUILDER_H
92 
93 //#include "steam/common.hpp"
94 #include "lib/error.hpp"
95 #include "lib/symbol.hpp"
96 //#include "steam/engine/channel-descriptor.hpp"
97 //#include "vault/gear/job.h"
98 #include "lib/several-builder.hpp"
99 #include "steam/engine/proc-id.hpp"
100 #include "steam/engine/turnout.hpp"
104 #include "lib/test/test-helper.hpp"
105 #include "lib/format-string.hpp"
106 //#include "lib/util-foreach.hpp"
107 //#include "lib/iter-adapter.hpp"
108 //#include "lib/meta/function.hpp"
109 //#include "lib/itertools.hpp"
110 #include "lib/util.hpp"
111 
112 //#include <utility>
113 #include <functional>
114 //#include <array>
115 #include <vector>
116 #include <string>
117 
118 
119 namespace steam {
120 namespace engine {
121  namespace err = lumiera::error;
122 
123  using StrView = std::string_view;
124  using std::forward;
125  using lib::Literal;
126  using lib::Several;
127  using lib::Depend;
128  using util::_Fmt;
129  using util::max;
130 
131 
132  namespace {// Introspection helpers....
133 
134  using lib::meta::_Fun;
135  using lib::meta::is_BinaryFun;
136  using std::remove_reference_t;
137 
146  template<class FUN>
147  struct _ProcFun
148  {
149  static_assert(_Fun<FUN>() , "something funktion-like required");
150  static_assert(is_BinaryFun<FUN>() , "function with two arguments expected");
151 
152  using ArgI = remove_reference_t<typename _Fun<FUN>::Args::List::Head>;
153  using ArgO = remove_reference_t<typename _Fun<FUN>::Args::List::Tail::Head>;
154 
155  template<class ARG>
157  {
158  static_assert(not sizeof(ARG), "processing function expected to take array-of-buffer-pointers");
159  };
160  template<class BUF, size_t N>
161  struct MatchBuffArray<std::array<BUF*,N>>
162  {
163  using Buff = BUF;
164  enum{ SIZ = N };
165  };
166 
167  using BuffI = typename MatchBuffArray<ArgI>::Buff;
168  using BuffO = typename MatchBuffArray<ArgO>::Buff;
169 
170  enum{ FAN_I = MatchBuffArray<ArgI>::SIZ
171  , FAN_O = MatchBuffArray<ArgO>::SIZ
172  };
173  };
174 
175 
185  template<class FUN>
186  inline constexpr uint
188  {
189  using _F = _ProcFun<FUN>;
190  auto constexpr bound = std::max (_F::FAN_I, _F::FAN_O);
191  static_assert (bound <= 10,
192  "Limitation of template instances exceeded");
193  return bound < 3? bound
194  : bound < 6? 5
195  : 10;
196  }
197  }//(End)Introspection helpers.
198 
199 
210  template<class MAN, class FUN>
212  : MAN
213  {
214  using BuffI = typename _ProcFun<FUN>::BuffI;
215  using BuffO = typename _ProcFun<FUN>::BuffO;
216 
217  enum{ N = MAN::STORAGE_SIZ
218  , FAN_I = _ProcFun<FUN>::FAN_I
219  , FAN_O = _ProcFun<FUN>::FAN_O
220  };
221 
222  static_assert(FAN_I <= N and FAN_O <= N);
223 
224  using ArrayI = std::array<BuffI*, FAN_I>;
225  using ArrayO = std::array<BuffO*, FAN_O>;
226 
227 
228  FUN process;
229 
230  ArrayI inParam;
231  ArrayO outParam;
232 
233  template<typename...INIT>
234  SimpleFunctionInvocationAdapter (INIT&& ...funSetup)
235  : process{forward<INIT> (funSetup)...}
236  { }
237 
238 
239  void
240  connect (uint fanIn, uint fanOut)
241  {
242  REQUIRE (fanIn >= FAN_I and fanOut >= FAN_O);
243  for (uint i=0; i<FAN_I; ++i)
244  inParam[i] = & MAN::inBuff[i].template accessAs<BuffI>();
245  for (uint i=0; i<FAN_O; ++i)
246  outParam[i] = & MAN::outBuff[i].template accessAs<BuffO>();
247  }
248 
249  void
250  invoke()
251  {
252  process (inParam, outParam);
253  }
254  };
255 
266  template<uint N, class FUN>
269  {
270  using Manifold = FeedManifold<N>;
272  enum{ MAX_SIZ = N };
273 
274  std::function<Feed()> buildFeed;
275 
282  : buildFeed{[=]{ return Feed{fun}; }}
283  { }
284  };
285 
286 
287 
288 
289  template<class POL, class I, class E=I>
291 
292  template<uint siz>
293  using SizMark = std::integral_constant<uint,siz>;
294 
295 
297 
307  template<class PAR, class BUILD, uint siz>
308  struct PatternData
309  : PAR
310  {
311  BUILD buildEntry;
312 
313  uint size() { return 1 + PAR::size(); }
314 
315  template<class DAB>
316  void
317  collectEntries (DAB& dataBuilder, uint cntElm =0, uint maxSiz =0)
318  {
319  PAR::collectEntries (dataBuilder, cntElm+1, max (siz,maxSiz));
320  buildEntry (dataBuilder);
321  }
322 
323 
324  PatternData(PAR&& predecessor, BUILD&& entryBuilder)
325  : PAR{move (predecessor)}
326  , buildEntry{move (entryBuilder)}
327  { }
328  };
329 
335  {
336  uint size() { return 0; }
337 
338  template<class DAB>
339  void
340  collectEntries (DAB& dataBuilder, uint cntElm, uint maxSiz)
341  {
342  dataBuilder.reserve (cntElm, maxSiz);
343  }
344  };
345 
346 
347 
348 
349  template<uint N, class FUN>
351 
352 
367  template<class POL, uint N, class FUN>
370  {
371  using FunSpec = _ProcFun<FUN>;
373  static constexpr SizMark<sizeof(TurnoutWeaving)> sizMark{};
374  static constexpr uint FAN_I = FunSpec::FAN_I;
375  static constexpr uint FAN_O = FunSpec::FAN_O;
376 
377 
378  using TypeMarker = std::function<BuffDescr(BufferProvider&)>;
380 
381  DataBuilder<POL, PortRef> leadPorts;
382  std::vector<TypeMarker> buffTypes;
383  std::vector<ProviderRef> providers;
384 
385  uint resultSlot{0};
386 
387  Depend<EngineCtx> ctx;
388 
389  StrView nodeSymb_;
390  StrView portSpec_;
391  FUN fun_;
392 
393  template<typename...INIT>
394  WeavingBuilder(FUN&& init, StrView nodeSymb, StrView portSpec, INIT&& ...alloInit)
395  : leadPorts{forward<INIT> (alloInit)...}
396  , nodeSymb_{nodeSymb}
397  , portSpec_{portSpec}
398  , fun_{move(init)}
399  { }
400 
402  attachToLeadPort (ProcNode& lead, uint portNr)
403  {
404  if (leadPorts.size() >= FAN_I)
405  throw err::Logic{_Fmt{"Builder: attempt to add further input, "
406  "but all %d »input slots« of the processing function are already connected."}
407  % FAN_I
408  };
409  PortRef portRef{lead.getPort (portNr)};
410  leadPorts.append (portRef);
411  return move(*this);
412  }
413 
414  template<class BU>
416  appendBufferTypes (uint cnt)
417  {
418  if (buffTypes.size()+cnt > FAN_O)
419  throw err::Logic{_Fmt{"Builder: attempt add %d further output buffers, "
420  "while %d of %d possible outputs are already connected."}
421  % cnt % buffTypes.size() % FAN_O
422  };
423  while (cnt--)
424  buffTypes.emplace_back([](BufferProvider& provider)
425  { return provider.getDescriptor<BU>(); });
426  ENSURE (buffTypes.size() <= N);
427  return move(*this);
428  }
429 
431  fillRemainingBufferTypes()
432  {
433  using BuffO = typename FunSpec::BuffO;
434  uint cnt = FAN_O - buffTypes.size();
435  return appendBufferTypes<BuffO>(cnt);
436  }
437 
439  connectRemainingInputs (DataBuilder<POL, ProcNodeRef>& knownLeads, uint defaultPort)
440  {
441  REQUIRE (leadPorts.size() <= FAN_I);
442  uint cnt = FAN_I - leadPorts.size();
443  if (FAN_I > knownLeads.size())
444  throw err::Logic{_Fmt{"Builder: attempt to auto-connect %d further »input slots«, "
445  "but this ProcNode has only %d predecessor nodes, while the "
446  "given processing function expects %d inputs."}
447  % cnt % knownLeads.size() % FAN_I
448  };
449  while (cnt--)
450  attachToLeadPort (knownLeads[leadPorts.size()], defaultPort);
451  return move(*this);
452  }
453 
455  selectResultSlot (uint idx)
456  {
457  this->resultSlot = idx;
458  return move(*this);
459  }
460 
461 
462  auto
463  build()
464  {
465  // discard excess storage prior to allocating the output types sequence
466  leadPorts.shrinkFit();
467 
468  maybeFillDefaultProviders (buffTypes.size());
469  REQUIRE (providers.size() == buffTypes.size());
470  auto outTypes = DataBuilder<POL, BuffDescr>{leadPorts.policyConnect()}
471  .reserve (buffTypes.size());
472  uint i=0;
473  for (auto& typeConstructor : buffTypes)
474  outTypes.append (
475  typeConstructor (providers[i++]));
476 
477  ENSURE (leadPorts.size() <= N);
478  ENSURE (leadPorts.size() == FunSpec::FAN_I);
479  ENSURE (outTypes.size() <= N);
480  ENSURE (outTypes.size() == FunSpec::FAN_O);
481 
482  using PortDataBuilder = DataBuilder<POL, Port>;
483  // provide a free-standing functor to build a suitable Port impl (≙Turnout)
484  return [leads = move(leadPorts.build())
485  ,types = move(outTypes.build())
486  ,procFun = move(fun_)
487  ,resultIdx = resultSlot
488  ,procID = ProcID::describe (nodeSymb_,portSpec_)
489  ]
490  (PortDataBuilder& portData) mutable -> void
491  {
492  portData.template emplace<TurnoutWeaving> (procID
493  ,move(leads)
494  ,move(types)
495  ,resultIdx
496  ,move(procFun)
497  );
498  };
499  }
500 
501  private:
502  void
503  maybeFillDefaultProviders (size_t maxSlots)
504  {
505  for (uint i=providers.size(); i < maxSlots; ++i)
506  providers.emplace_back (ctx().mem);
507  }
508  };
510 
511 
512 
513 }}// namespace steam::engine
514 #endif /*STEAM_ENGINE_WEAVING_PATTERN_BUILDER_H*/
SeveralBuilder && reserve(size_t cntElm=1, size_t elmSiz=reqSiz< TY >())
ensure up-front that a desired capacity is allocated
Processing structure to activate a Render Node and produce result data.
Definition: turnout.hpp:202
Several< I > build()
Terminal Builder: complete and lock the collection contents.
DirectFunctionInvocation(FUN fun)
when building the Turnout, prepare the invocation adapter
Typical base configuration for a Weaving-Pattern chain:
Standard implementation for a Weaving Pattern to connect the input and output data feeds (buffers) in...
Definition: turnout.hpp:114
Helper to pick up the parameter dimensions from the processing function.
Obsolete, to be rewritten /////TICKET #826.
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
STL namespace.
Types marked with this mix-in may be moved but not copied.
Definition: nocopy.hpp:49
A low-level Builder to prepare and adapt for a specific node invocation.
Front-end for printf-style string template interpolation.
Helper for uniform access to function signature types.
Definition: function.hpp:99
Steam-Layer implementation namespace root.
A front-end for using printf-style formatting.
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:280
Metadata interface to generate symbolic and hash ID tags for media processing steps.
Adapter to handle a simple yet common setup for media processing.
Fixed standard setup used in each Port of the Render Node to generate data.
static ProcID & describe(StrView nodeSymb, StrView portSpec)
build and register a processing ID descriptor
Definition: proc-node.cpp:69
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:190
Abstraction: Fixed array of elements.
Definition: several.hpp:156
BuffDescr getDescriptor(ARGS ...args)
define a "buffer type" for automatically creating an instance of the template type embedded into the ...
Marker types to indicate a literal string and a Symbol.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
constexpr uint manifoldSiz()
Pick a suitable size for the FeedManifold to accommodate the given function.
Builder to create and populate a lib::Several<I>.
Recursive functional data structure to collect weaving pattern data and finally to emplace a Turnout ...
Extension to allow placing objects right into the buffers, taking ownership.
A collection of frequently used helper functions to support unit testing.
Dependency context to hold global parameters and services for the render engine.
Lumiera error handling (C++ interface).
Key abstraction of the Render Engine: A Data processing Node.
Definition: proc-node.hpp:154
Interface: a facility providing and managing working buffers for media calculations.
SeveralBuilder && shrinkFit()
discard excess reserve capacity.
uint maxSlots(0)
number of different registered Types
Data recursion end: prime the port data storage by reserving appropriate storage to hold all known Tu...
SeveralBuilder && append(VAL &&val, VALS &&...vals)
append copies of one or several arbitrary elements
Builder to create and populate instances of the lib::Several container.
Abstraction to represent buffer management and lifecycle within the render engine.