37#include <boost/functional/hash.hpp>
38#include <unordered_set>
51 using boost::hash_combine;
55 std::unordered_set<ProcID> procRegistry;
56 std::unordered_set<string> symbRegistry;
62 auto res = symbRegistry.emplace (symbol);
73 using std::regex_match;
76 const regex SPEC_CONTENT{R
"_([^,\\\(\)\[\]{}<>"]+)_", regex::optimize};
77 const regex NON_QUOTE {R
"_([^"\\]+)_" , regex::optimize};
78 const regex ESCAPE {R
"_(\\.)_" , regex::optimize};
79 const regex COMMA {R
"_(,)_" , regex::optimize};
80 const regex D_QUOTE {R
"_(")_" , regex::optimize};
85 template<
char OPE,
char CLO>
90 regex OPENING{esc+OPE};
91 regex CLOSING{esc+CLO};
92 regex NON_PAREN{R
"_([^\\)_"+esc+OPE+esc+CLO+"]+"};
94 static auto paren = expectResult<Nil>();
100 paren =
accept_bracket(OPENING,CLOSING, parenContent).bind([](
auto){
return Nil{}; });
107 .alt(syntaxBracketed<
'(',
')'>())
108 .alt(syntaxBracketed<
'<',
'>'>())
109 .alt(syntaxBracketed<
'[',
']'>())
110 .alt(syntaxBracketed<
'{',
'}'>())
115 const regex REPEAT_SPEC {R
"_(^(.+)\s*/(\d+)\s*$)_", regex::optimize};
124 struct RepetitionExpander
129 mutable uint repeat_{0};
130 mutable std::smatch mat_;
137 if (not regex_match (*Core::srcIter(), mat_, REPEAT_SPEC))
138 return *Core::srcIter();
141 repeat_ = boost::lexical_cast<uint>(mat_.str(2));
143 return StrView(& *mat_[1].first, mat_[1].length());
163 evaluateArgSeq (std::vector<string>& parsedArgTerms)
165 auto several = lib::makeSeveral<const string>();
167 .processingLayer<RepetitionExpander>()
168 .
foreach([&](
StrView s){ several.emplace<
string>(s); });
169 return several.build();
195 REQUIRE (not isnil (nodeSymb));
196 REQUIRE (not isnil (portSpec));
197 REQUIRE (not contains (nodeSymb,
' '));
198 auto p = portSpec.find(
'(');
199 if (p == string::npos)
200 throw err::Invalid{_Fmt{
"Spec for processing operation must contain at least one argument list. "
202 % nodeSymb % portSpec
204 auto res = procRegistry.emplace (ProcID{nodeSymb, portSpec.substr(0,p), portSpec.substr(p), extAttrib});
208 dedupSymbol (
entry.nodeName_);
209 dedupSymbol (
entry.argLists_);
211 dedupSymbol (
entry.portQual_);
218 : nodeName_{nodeSymb}
219 , portQual_{portQual}
220 , argLists_{argLists}
232 HashVal hash = boost::hash_value (procID.nodeName_);
233 if (not
isnil(procID.portQual_))
234 hash_combine (
hash, procID.portQual_);
235 hash_combine (
hash, procID.argLists_);
240 ProcID::genProcName()
const
242 std::ostringstream buffer;
243 buffer << genNodeSymbol()
249 ProcID::genProcSpec()
const
251 std::ostringstream buffer;
252 buffer << genNodeSymbol()
259 ProcID::genNodeName()
const
261 return string{nodeName_};
265 ProcID::genNodeSymbol()
const
267 auto p = nodeName_.find(
':');
268 return p == string::npos?
string{nodeName_}
269 :
string{nodeName_.substr(p+1)};
273 ProcID::genNodeDomain()
const
275 auto p = nodeName_.find(
':');
276 return p == string::npos?
string{}
277 :
string{nodeName_.substr(0,p)};
281 ProcID::genQualifier()
const
283 std::ostringstream buffer;
284 if (not
isnil(portQual_))
285 buffer <<
'.' << portQual_;
292 procID (ProcNode& node)
300 ProcID::genNodeSpec (Leads& leads)
const
302 std::ostringstream buffer;
304 if (1 != leads.size())
305 buffer << genSrcSpec(leads);
308 ProcNode& p{leads.front().get()};
310 << procID(p).genNodeName()
311 << procID(p).genSrcSpec(
318 ProcID::genSrcSpec (Leads& leads)
const
320 return isnil(leads)?
string{
"-◎"}
324 .expandAll([](ProcNode& n){
return explore(
watch(n).leads()); })
325 .filter ([](ProcNode& n){
return watch(n).
isSrc(); })
326 .
transform([](ProcNode& n){
return procID(n).nodeName_;})
334 ProcID::genArgModel()
const
337 auto argSpecSyntax =
accept(argListSyntax)
339 .bind([](
auto model) -> ProcID::ArgModel
341 auto [list1,list2] = model;
343 return {evaluateArgSeq(list1), evaluateArgSeq(*list2)};
345 return {emptyArgSeq(), evaluateArgSeq(list1)};
348 argSpecSyntax.parse (argLists_);
349 if (not argSpecSyntax.success())
350 throw err::Invalid{_Fmt{
"Unable to parse argument list. "
352 % genProcName() % argLists_
354 return argSpecSyntax.extractResult();
365 ProcNodeDiagnostic::getNodeSpec()
367 REQUIRE (not
isnil(ports()));
368 return ports().front().procID.genNodeSpec (leads());
372 ProcNodeDiagnostic::getNodeName()
374 REQUIRE (not
isnil(ports()));
375 return ports().front().procID.genNodeName();
379 ProcNodeDiagnostic::getNodeHash()
381 UNIMPLEMENTED (
"calculate an unique hash-key to designate this node");
389 ProcNodeDiagnostic::getPortSpec (
uint portIdx)
391 auto& p{n_.wiring_.ports};
392 return portIdx < p.size()? p[portIdx].procID.genProcSpec()
393 : util::FAILURE_INDICATOR;
397 ProcNodeDiagnostic::getPortHash (
uint portIdx)
399 UNIMPLEMENTED (
"calculate an unique, stable and reproducible hash-key to identify the Turnout");
406 using _DummyProc = void(&)(Nil*);
407 using _DummyProto = FeedPrototype<_DummyProc>;
408 using _DummyMediaWeaving = MediaWeavingPattern<_DummyProto>;
409 using _RecastMediaWeaving = _TurnoutDiagnostic<_DummyMediaWeaving>;
412 using _DummyParamWeaving = ParamWeavingPattern<_EmptySpec>;
413 using _RecastParamWeaving = _TurnoutDiagnostic<_DummyParamWeaving>;
432 PortDiagnostic::srcPorts()
434 if (p_.procID.hasManifoldPatt())
436 auto [leads,types] = _RecastMediaWeaving::accessInternal (p_);
440 if (p_.procID.hasProxyPatt())
442 Port& delegate = std::get<0>(_RecastParamWeaving::accessInternal (p_));
443 return watch(delegate).srcPorts();
446 return EMPTY_PRECURSORS;
454 PortDiagnostic::getProcSpec()
456 return p_.procID.genProcSpec();
460 PortDiagnostic::getProcName()
462 return p_.procID.genProcName();
466 PortDiagnostic::getProcHash()
468 UNIMPLEMENTED (
"calculate an unique, stable and reproducible hash-key to identify the Turnout");
475 ProcNodeDiagnostic::watchLead (
uint leadIdx)
477 if (leadIdx >= leads().size())
478 throw err::Invalid{_Fmt{
"Lead-# %d >= %d (available lead-nodes)."}
479 % leadIdx % leads().size()};
480 return watch (leads()[leadIdx]);
484 ProcNodeDiagnostic::watchPort (
uint portIdx)
486 if (portIdx >= ports().size())
487 throw err::Invalid{_Fmt{
"Port-idx %d >= %d (available Ports)."}
488 % portIdx % ports().size()};
489 return watch (ports()[portIdx]);
493 PortDiagnostic::watchLead (
uint leadIdx)
495 auto& leadPorts = srcPorts();
496 if (leadIdx >= leadPorts.size())
497 throw err::Invalid{_Fmt{
"Lead-Port# %d >= %d (available src-ports)."}
498 % leadIdx % leadPorts.size()};
499 return watch (leadPorts[leadIdx]);
503 PortDiagnostic::verify_connected (
uint input, Port& tarPort)
505 auto& leadPorts = srcPorts();
506 return input < leadPorts.size()
507 and leadPorts[input] == tarPort;
511 PortDiagnostic::verify_connected (Port& tarPort)
513 for (Port& port : srcPorts())
537 _ConCheck::operator bool()
539 auto validPort = [
this](
uint idx) {
return idx < anchor.ports().size(); };
540 auto validLead = [
this](
uint idx) {
return idx < anchor.leads().size(); };
541 auto validSrc = [
this](
uint pNo
542 ,
uint sNo) {
return sNo < anchor.watchPort(pNo).srcPorts().size(); };
543 auto validSrcP = [
this](ProcNode& lead
546 auto find_link = [](
auto& seq1,
auto& seq2)
549 .transform([&](
auto& elm){
return contains (seq2, *elm); })
555 if (portNo and srcNo and srcNode and srcPNo)
556 return validPort(*portNo)
557 and validSrc (*portNo, *srcNo)
558 and validSrcP(*srcNode,*srcPNo)
559 and anchor.watchPort(*portNo).srcPorts()[*srcNo]
562 if (portNo and srcNo and leadNo and srcPNo)
563 return validPort(*portNo)
564 and validSrc (*portNo,*srcNo)
565 and validLead(*leadNo)
566 and validSrcP(anchor.leads()[*leadNo], *srcPNo)
567 and anchor.watchPort(*portNo).srcPorts()[*srcNo]
568 == anchor.watchLead(*leadNo).ports()[*srcPNo];
570 if (portNo and srcNo and srcPort)
571 return validPort(*portNo)
572 and validSrc (*portNo,*srcNo)
573 and anchor.watchPort(*portNo).srcPorts()[*srcNo]
576 if (portNo and srcNo and srcNode)
577 return validPort(*portNo)
578 and validSrc (*portNo,*srcNo)
580 ,anchor.watchPort(*portNo).srcPorts()[*srcNo]);
582 if (portNo and srcNo and leadNo)
583 return validPort(*portNo)
584 and validSrc (*portNo,*srcNo)
585 and validLead(*leadNo)
586 and
contains (anchor.watchLead(*leadNo).ports()
587 ,anchor.watchPort(*portNo).srcPorts()[*srcNo]);
589 if (portNo and srcNo)
590 return validPort(*portNo)
591 and validSrc (*portNo,*srcNo);
593 if (portNo and srcNode and srcPNo)
594 return validPort(*portNo)
595 and validSrcP(*srcNode,*srcPNo)
596 and
contains (anchor.watchPort(*portNo).srcPorts()
599 if (portNo and leadNo and srcPNo)
600 return validPort(*portNo)
601 and validLead(*leadNo)
602 and validSrcP(anchor.leads()[*leadNo], *srcPNo)
603 and
contains (anchor.watchPort(*portNo).srcPorts()
604 ,anchor.watchLead(*leadNo).ports()[*srcPNo]);
606 if (portNo and srcPort)
607 return validPort(*portNo)
608 and
contains (anchor.watchPort(*portNo).srcPorts()
611 if (portNo and srcNode)
612 return validPort(*portNo)
614 ,anchor.watchPort(*portNo).srcPorts());
616 if (portNo and leadNo)
617 return validPort(*portNo)
618 and validLead(*leadNo)
619 and find_link(anchor.watchLead(*leadNo).ports()
620 ,anchor.watchPort(*portNo).srcPorts());
623 return validPort(*portNo)
624 and not anchor.watchPort(*portNo).isSrc();
626 if (srcNode and leadNo)
627 return validLead(*leadNo)
628 and anchor.leads()[*leadNo]
Adapter to dress up an existing »Lumiera Forward Iterator« as »state core«.
Abstraction: Fixed array of elements.
Derived specific exceptions within Lumiera's exception hierarchy.
virtual ~Port()
this is an interface
static ProcID & describe(StrView nodeSymb, StrView portSpec, ProcAttrib extAttrib=ProcAttrib{})
build and register a processing ID descriptor
ProcID(StrView nodeSymb, StrView portQual, StrView argLists, ProcAttrib)
A front-end for using printf-style formatting.
Building tree expanding and backtracking evaluations within hierarchical scopes.
_TransformIterT< IT, FUN >::Iter transform(IT &&source, FUN processingFunc)
pipes a given Lumiera Forward Iterator through a transformation function and wraps the resulting tran...
auto explore(IT &&srcSeq)
start building a IterExplorer by suitably wrapping the given iterable source.
size_t HashVal
a STL compatible hash value
ProcNodeDiagnostic watch(ProcNode &theNode)
AnyPair entry(Query< TY > const &query, typename WrapReturn< TY >::Wrapper &obj)
helper to simplify creating mock table entries, wrapped correctly
Steam-Layer implementation namespace root.
auto accept_repeated(uint min, uint max, SPEC1 &&delimDef, SPEC2 &&clauseDef)
Start Syntax clause with a repeated sub-clause, with separator and repetition limit; repetitions ∊ [m...
auto accept(SPEC &&clauseDef)
===== Syntax clause builder DSL =====
auto accept()
empty Syntax clause to start further definition
auto accept_bracket(SPEC1 &&openDef, SPEC2 &&closeDef, SPEC3 &&bodyDef)
Start Syntax with a sub-clause enclosed into a bracketing construct.
auto expectResult()
Setup an assignable, recursive Syntax clause, initially empty.
bool has_any(IT i, IT end, FUN predicate)
Existential quantification: check if any element of a collection satisfies the given predicate.
bool isSameObject(A const &a, B const &b)
compare plain object identity, based directly on the referee's memory identities.
bool contains(MAP &map, typename MAP::key_type const &key)
shortcut for containment test on a map
OBJ * unConst(const OBJ *)
shortcut to save some typing when having to define const and non-const variants of member functions
string join(COLL &&coll, string const &delim=", ")
enumerate a collection's contents, separated by delimiter.
bool isnil(lib::time::Duration const &dur)
Construction kit to establish a set of parameters pre-computed prior to invocation of nested nodes.
Convenience wrappers and definitions for parsing structured definitions.
Metadata interface to generate symbolic and hash ID tags for media processing steps.
Interface to the processing nodes and the Render Nodes network.
Builder to create and populate instances of the lib::Several container.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...