Vuo  2.3.2
VuoNodeRegistry.cc
Go to the documentation of this file.
1 
10 #include "VuoNodeRegistry.hh"
11 
12 #include <dlfcn.h>
13 #include <sstream>
14 #include "VuoCompositionDiff.hh"
15 #include "VuoException.hh"
17 #include "VuoRuntimeState.hh"
18 #include "VuoRuntimeUtilities.hh"
19 
20 const unsigned long VuoNodeRegistry::topLevelCompositionIndex = ULONG_MAX;
21 const unsigned long VuoNodeRegistry::invalidCompositionIndex = ULONG_MAX - 1;
22 
27 {
28  this->persistentState = persistentState;
29  vuoTopLevelCompositionIdentifier = NULL;
30 }
31 
37 void VuoNodeRegistry::updateCompositionSymbols(void *compositionBinaryHandle)
38 {
39  ostringstream errorMessage;
40 
41  vuoTopLevelCompositionIdentifierType *vuoTopLevelCompositionIdentifierPtr = (vuoTopLevelCompositionIdentifierType *) dlsym(compositionBinaryHandle, "vuoTopLevelCompositionIdentifier");
42  if (! vuoTopLevelCompositionIdentifierPtr)
43  {
44  errorMessage << "The composition couldn't be started because its vuoTopLevelCompositionIdentifier variable couldn't be found : " << dlerror();
45  throw VuoException(errorMessage.str());
46  }
47  vuoTopLevelCompositionIdentifier = *vuoTopLevelCompositionIdentifierPtr;
48 }
49 
54 const char * VuoNodeRegistry::defaultToTopLevelCompositionIdentifier(const char *compositionIdentifier)
55 {
56  return (strlen(compositionIdentifier) > 0 ? compositionIdentifier : vuoTopLevelCompositionIdentifier);
57 }
58 
66 void VuoNodeRegistry::splitCompositionIdentifier(const string &compositionIdentifier, string &parentCompositionIdentifier, string &nodeIdentifier)
67 {
68  size_t pos = compositionIdentifier.rfind("/");
69  if (pos != string::npos)
70  {
71  parentCompositionIdentifier = compositionIdentifier.substr(0, pos);
72  nodeIdentifier = compositionIdentifier.substr(pos + strlen("/"));
73  }
74  else
75  {
76  parentCompositionIdentifier = compositionIdentifier;
77  nodeIdentifier = "";
78  }
79 }
80 
84 string VuoNodeRegistry::buildCompositionIdentifier(const string &parentCompositionIdentifier, const string &nodeIdentifier)
85 {
86  return parentCompositionIdentifier + "/" + nodeIdentifier;
87 }
88 
94 void VuoNodeRegistry::splitPortIdentifier(const string &portIdentifier, string &nodeIdentifier, string &portName)
95 {
96  size_t pos = portIdentifier.rfind(":");
97  if (pos != string::npos)
98  {
99  nodeIdentifier = portIdentifier.substr(0, pos);
100  portName = portIdentifier.substr(pos + strlen(":"));
101  }
102 }
103 
110 void VuoNodeRegistry::addNodeMetadata(const char *compositionIdentifier, const char *nodeIdentifier,
111  NodeContext *(*compositionCreateContextForNode)(unsigned long),
112  void (*compositionSetPortValue)(VuoCompositionState *, const char *, const char *, bool, bool, bool, bool, bool),
113  char * (*compositionGetPortValue)(VuoCompositionState *, const char *, int, bool),
114  void (*compositionFireTriggerPortEvent)(VuoCompositionState *, const char *),
115  void (*compositionReleasePortData)(void *, unsigned long))
116 {
117  NodeMetadata nodeMetadata;
118  nodeMetadata.identifier = nodeIdentifier;
119  nodeMetadata.compositionCreateContextForNode = compositionCreateContextForNode;
120  nodeMetadata.compositionSetPortValue = compositionSetPortValue;
121  nodeMetadata.compositionGetPortValue = compositionGetPortValue;
122  nodeMetadata.compositionFireTriggerPortEvent = compositionFireTriggerPortEvent;
123  nodeMetadata.compositionReleasePortData = compositionReleasePortData;
124  nodeMetadatas[compositionIdentifier].push_back(nodeMetadata);
125 }
126 
131 void VuoNodeRegistry::addPortMetadata(const char *compositionIdentifier, const char *portIdentifier, const char *portName,
132  unsigned long typeIndex, const char *initialValue)
133 {
134  PortMetadata portMetadata = { portIdentifier, portName, typeIndex, initialValue };
135  nodeMetadatas[compositionIdentifier].back().portMetadatas.push_back(portMetadata);
136 }
137 
141 string VuoNodeRegistry::getNodeIdentifierForIndex(const char *compositionIdentifier, unsigned long nodeIndex)
142 {
143  if (nodeIndex == topLevelCompositionIndex)
144  return "";
145 
146  map<string, vector<NodeMetadata> >::iterator iter1 = nodeMetadatas.find(compositionIdentifier);
147  if (iter1 != nodeMetadatas.end())
148  if (nodeIndex < iter1->second.size())
149  return iter1->second[nodeIndex].identifier;
150 
151  VUserLog("Couldn't find identifier for node %s/%lu", compositionIdentifier, nodeIndex);
152  return "";
153 }
154 
158 unsigned long VuoNodeRegistry::getNodeIndexForIdentifier(const string &compositionIdentifier, const string &nodeIdentifier)
159 {
160  if (nodeIdentifier.empty())
161  return topLevelCompositionIndex;
162 
163  map<string, vector<NodeMetadata> >::iterator iter1 = nodeMetadatas.find(compositionIdentifier);
164  if (iter1 != nodeMetadatas.end())
165  for (unsigned long i = 0; i < iter1->second.size(); ++i)
166  if (iter1->second[i].identifier == nodeIdentifier)
167  return i;
168 
169  VUserLog("Couldn't find index for node %s", buildCompositionIdentifier(compositionIdentifier, nodeIdentifier).c_str());
170  return invalidCompositionIndex;
171 }
172 
176 const VuoNodeRegistry::NodeMetadata * VuoNodeRegistry::getNodeMetadataForPort(const string &compositionIdentifier, const string &portIdentifier)
177 {
178  string nodeIdentifier, portName;
179  splitPortIdentifier(portIdentifier, nodeIdentifier, portName);
180 
181  map<string, vector<NodeMetadata> >::iterator iter1 = nodeMetadatas.find(compositionIdentifier);
182  if (iter1 != nodeMetadatas.end())
183  for (unsigned long i = 0; i < iter1->second.size(); ++i)
184  if (iter1->second[i].identifier == nodeIdentifier)
185  return &(iter1->second[i]);
186 
187  VUserLog("Couldn't find node metadata for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
188  return NULL;
189 }
190 
194 string VuoNodeRegistry::getCompositionIdentifierForHash(unsigned long compositionIdentifierHash)
195 {
196  map<unsigned long, string>::iterator iter1 = compositionIdentifierForHash.find(compositionIdentifierHash);
197  if (iter1 != compositionIdentifierForHash.end())
198  return iter1->second;
199 
200  VUserLog("Couldn't find composition identifier for hash %lu", compositionIdentifierHash);
201  return "";
202 }
203 
207 void VuoNodeRegistry::addNodeContext(const char *compositionIdentifier, unsigned long nodeIndex, NodeContext *nodeContext)
208 {
209  unsigned long compositionIdentifierHash = VuoRuntimeUtilities::hash(compositionIdentifier);
210 
211  map<unsigned long, map<unsigned long, NodeContext *> >::iterator iter1 = nodeContextForIndex.find(compositionIdentifierHash);
212  if (iter1 != nodeContextForIndex.end())
213  {
214  map<unsigned long, NodeContext *>::iterator iter2 = iter1->second.find(nodeIndex);
215  if (iter2 != iter1->second.end())
216  VUserLog("Context overwritten for node %s", buildCompositionIdentifier(compositionIdentifier, getNodeIdentifierForIndex(compositionIdentifier, nodeIndex)).c_str());
217  }
218 
219  nodeContextForIndex[compositionIdentifierHash][nodeIndex] = nodeContext;
220 
221  compositionIdentifierForHash[ VuoRuntimeUtilities::hash(compositionIdentifier) ] = compositionIdentifier;
222 }
223 
227 void VuoNodeRegistry::removeNodeContext(const char *compositionIdentifier, unsigned long nodeIndex)
228 {
229  unsigned long compositionIdentifierHash = VuoRuntimeUtilities::hash(compositionIdentifier);
230 
231  map<unsigned long, map<unsigned long, NodeContext *> >::iterator iter1 = nodeContextForIndex.find(compositionIdentifierHash);
232  if (iter1 != nodeContextForIndex.end())
233  {
234  map<unsigned long, NodeContext *>::iterator iter2 = iter1->second.find(nodeIndex);
235  if (iter2 != iter1->second.end())
236  {
237  iter1->second.erase(iter2);
238  if (iter1->second.empty())
239  nodeContextForIndex.erase(iter1);
240 
241  string nodeIdentifier = getNodeIdentifierForIndex(compositionIdentifier, nodeIndex);
242  string subcompositionIdentifier = buildCompositionIdentifier(compositionIdentifier, nodeIdentifier);
243  unsigned long subcompositionIdentifierHash = VuoRuntimeUtilities::hash(subcompositionIdentifier.c_str());
244  map<unsigned long, string>::iterator ciIter = compositionIdentifierForHash.find(subcompositionIdentifierHash);
245  if (ciIter != compositionIdentifierForHash.end())
246  compositionIdentifierForHash.erase(ciIter);
247 
248  return;
249  }
250  }
251 
252  VUserLog("Couldn't find context for node %s", buildCompositionIdentifier(compositionIdentifier, getNodeIdentifierForIndex(compositionIdentifier, nodeIndex)).c_str());
253 }
254 
258 void VuoNodeRegistry::relocateNodeContext(const char *compositionIdentifier, unsigned long nodeIndex)
259 {
260  unsigned long compositionIdentifierHash = VuoRuntimeUtilities::hash(compositionIdentifier);
261 
262  map<unsigned long, map<unsigned long, NodeContext *> >::iterator iter1 = nodeContextForIndex.find(compositionIdentifierHash);
263  if (iter1 != nodeContextForIndex.end())
264  {
265  map<unsigned long, NodeContext *>::iterator iter2 = iter1->second.find(nodeIndex);
266  if (iter2 != iter1->second.end())
267  {
268  string nodeIdentifier = getNodeIdentifierForIndex(compositionIdentifier, nodeIndex);
269  carriedOverNodeContextForIdentifier[compositionIdentifier][nodeIdentifier] = iter2->second;
270  iter1->second.erase(iter2);
271 
272  if (iter1->second.empty())
273  nodeContextForIndex.erase(iter1);
274 
275  return;
276  }
277  }
278 
279  VUserLog("Couldn't find context for node %s", buildCompositionIdentifier(compositionIdentifier, getNodeIdentifierForIndex(compositionIdentifier, nodeIndex)).c_str());
280 }
281 
286 NodeContext * VuoNodeRegistry::carryOverNodeContext(const char *oldCompositionIdentifier, const char *newCompositionIdentifier,
287  unsigned long nodeIndex)
288 {
289  NodeContext *nodeContext = NULL;
290  string nodeIdentifier = getNodeIdentifierForIndex(newCompositionIdentifier, nodeIndex);
291 
292  {
293  bool found = false;
294  map<string, map<string, NodeContext *> >::iterator coIter1 = carriedOverNodeContextForIdentifier.find(oldCompositionIdentifier);
295  if (coIter1 != carriedOverNodeContextForIdentifier.end())
296  {
297  map<string, NodeContext *>::iterator coIter2 = coIter1->second.find(nodeIdentifier);
298  if (coIter2 != coIter1->second.end())
299  {
300  nodeContext = coIter2->second;
301  coIter1->second.erase(coIter2);
302  addNodeContext(newCompositionIdentifier, nodeIndex, nodeContext);
303  found = true;
304 
305  if (coIter1->second.empty())
306  carriedOverNodeContextForIdentifier.erase(coIter1);
307  }
308  }
309 
310  if (! found)
311  VUserLog("Couldn't find context for node %s", buildCompositionIdentifier(oldCompositionIdentifier, nodeIdentifier).c_str());
312  }
313 
314  return nodeContext;
315 }
316 
320 NodeContext * VuoNodeRegistry::getNodeContext(const char *compositionIdentifier, unsigned long nodeIndex)
321 {
322  unsigned long compositionIdentifierHash = VuoRuntimeUtilities::hash(compositionIdentifier);
323 
324  map<unsigned long, map<unsigned long, NodeContext *> >::iterator iter1 = nodeContextForIndex.find(compositionIdentifierHash);
325  if (iter1 != nodeContextForIndex.end())
326  {
327  map<unsigned long, NodeContext *>::iterator iter2 = iter1->second.find(nodeIndex);
328  if (iter2 != iter1->second.end())
329  return iter2->second;
330  }
331 
332  VUserLog("Couldn't find context for node %s", buildCompositionIdentifier(compositionIdentifier, getNodeIdentifierForIndex(compositionIdentifier, nodeIndex)).c_str());
333  return NULL;
334 }
335 
339 NodeContext * VuoNodeRegistry::getCompositionContext(const char *compositionIdentifier)
340 {
341  string parentCompositionIdentifier, subcompositionNodeIdentifier;
342  splitCompositionIdentifier(compositionIdentifier, parentCompositionIdentifier, subcompositionNodeIdentifier);
343  unsigned long subcompositionNodeIndex = getNodeIndexForIdentifier(parentCompositionIdentifier, subcompositionNodeIdentifier);
344  return getNodeContext(parentCompositionIdentifier.c_str(), subcompositionNodeIndex);
345 }
346 
350 template<typename T>
351 bool VuoNodeRegistry::findCachedInfoForPort(const map<string, map<string, T> > &cachedInfoForPort, const string &compositionIdentifier,
352  const string &portIdentifier, typename map<string, T>::const_iterator &foundIter)
353 {
354  typename map<string, map<string, T> >::const_iterator compIter = cachedInfoForPort.find(compositionIdentifier);
355  if (compIter != cachedInfoForPort.end())
356  {
357  foundIter = compIter->second.find(portIdentifier);
358  if (foundIter != compIter->second.end())
359  return true;
360  }
361 
362  return false;
363 }
364 
368 void * VuoNodeRegistry::getDataForPort(const char *compositionIdentifier, const char *portIdentifier)
369 {
370  map<string, void *>::const_iterator foundIter;
371  bool found = findCachedInfoForPort<void *>(dataForPort, compositionIdentifier, portIdentifier, foundIter);
372  if (found)
373  return foundIter->second;
374 
375  VUserLog("Couldn't find data for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
376  return NULL;
377 }
378 
382 unsigned long VuoNodeRegistry::getNodeIndexForPort(const char *compositionIdentifier, const char *portIdentifier)
383 {
384  map<string, unsigned long>::const_iterator foundIter;
385  bool found = findCachedInfoForPort<unsigned long>(nodeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
386  if (found)
387  return foundIter->second;
388 
389  VUserLog("Couldn't find node index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
390  return 0;
391 }
392 
396 unsigned long VuoNodeRegistry::getTypeIndexForPort(const char *compositionIdentifier, const char *portIdentifier)
397 {
398  map<string, unsigned long>::const_iterator foundIter;
399  bool found = findCachedInfoForPort<unsigned long>(typeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
400  if (found)
401  return foundIter->second;
402 
403  VUserLog("Couldn't find type index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
404  return 0;
405 }
406 
410 void VuoNodeRegistry::addPortIdentifier(const char *compositionIdentifier, const string &portIdentifier,
411  void *data, unsigned long nodeIndex, unsigned long typeIndex)
412 {
413  map<string, void *>::const_iterator foundIter;
414  bool found = findCachedInfoForPort<void *>(dataForPort, compositionIdentifier, portIdentifier, foundIter);
415  if (found)
416  VUserLog("Cache overwritten for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
417 
418  dataForPort[compositionIdentifier][portIdentifier] = data;
419  nodeIndexForPort[compositionIdentifier][portIdentifier] = nodeIndex;
420  typeIndexForPort[compositionIdentifier][portIdentifier] = typeIndex;
421 }
422 
426 void VuoNodeRegistry::removePortIdentifier(const char *compositionIdentifier, const string &portIdentifier)
427 {
428  {
429  map<string, void *>::const_iterator foundIter;
430  bool found = findCachedInfoForPort<void *>(dataForPort, compositionIdentifier, portIdentifier, foundIter);
431  if (found)
432  {
433  dataForPort[compositionIdentifier].erase(portIdentifier);
434 
435  if (dataForPort[compositionIdentifier].empty())
436  dataForPort.erase(compositionIdentifier);
437  }
438  else
439  VUserLog("Couldn't find data for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
440  }
441  {
442  map<string, unsigned long>::const_iterator foundIter;
443  bool found = findCachedInfoForPort<unsigned long>(nodeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
444  if (found)
445  {
446  nodeIndexForPort[compositionIdentifier].erase(portIdentifier);
447 
448  if (nodeIndexForPort[compositionIdentifier].empty())
449  nodeIndexForPort.erase(compositionIdentifier);
450  }
451  else
452  VUserLog("Couldn't find node index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
453  }
454  {
455  map<string, unsigned long>::const_iterator foundIter;
456  bool found = findCachedInfoForPort<unsigned long>(typeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
457  if (found)
458  {
459  typeIndexForPort[compositionIdentifier].erase(portIdentifier);
460 
461  if (typeIndexForPort[compositionIdentifier].empty())
462  typeIndexForPort.erase(compositionIdentifier);
463  }
464  else
465  VUserLog("Couldn't find type index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
466  }
467 }
468 
472 void VuoNodeRegistry::relocatePortIdentifier(const char *compositionIdentifier, const string &portIdentifier)
473 {
474  {
475  map<string, void *>::const_iterator foundIter;
476  bool found = findCachedInfoForPort<void *>(dataForPort, compositionIdentifier, portIdentifier, foundIter);
477  if (found)
478  carriedOverDataForPort[compositionIdentifier][portIdentifier] = foundIter->second;
479  else
480  VUserLog("Couldn't find data for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
481  }
482  {
483  map<string, unsigned long>::const_iterator foundIter;
484  bool found = findCachedInfoForPort<unsigned long>(nodeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
485  if (found)
486  carriedOverNodeIndexForPort[compositionIdentifier][portIdentifier] = foundIter->second;
487  else
488  VUserLog("Couldn't find node index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
489  }
490  {
491  map<string, unsigned long>::const_iterator foundIter;
492  bool found = findCachedInfoForPort<unsigned long>(typeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
493  if (found)
494  carriedOverTypeIndexForPort[compositionIdentifier][portIdentifier] = foundIter->second;
495  else
496  VUserLog("Couldn't find type index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
497  }
498 
499  removePortIdentifier(compositionIdentifier, portIdentifier);
500 }
501 
506 void VuoNodeRegistry::carryOverPortIdentifier(const char *oldCompositionIdentifier, const char *newCompositionIdentifier,
507  const string &portIdentifier, unsigned long nodeIndex, unsigned long typeIndex)
508 {
509  map<string, void *>::const_iterator foundIter;
510  bool found = findCachedInfoForPort<void *>(carriedOverDataForPort, oldCompositionIdentifier, portIdentifier, foundIter);
511  if (! found)
512  {
513  VUserLog("Couldn't find cache for port %s", buildCompositionIdentifier(oldCompositionIdentifier, portIdentifier).c_str());
514  return;
515  }
516 
517  dataForPort[newCompositionIdentifier][portIdentifier] = carriedOverDataForPort[oldCompositionIdentifier][portIdentifier];
518  nodeIndexForPort[newCompositionIdentifier][portIdentifier] = nodeIndex;
519  typeIndexForPort[newCompositionIdentifier][portIdentifier] = typeIndex;
520 
521  removeCarriedOverPortIdentifier(oldCompositionIdentifier, portIdentifier);
522 }
523 
528 void VuoNodeRegistry::carryOverPortIdentifiersForNode(const char *oldCompositionIdentifier, const char *newCompositionIdentifier,
529  const string &nodeIdentifier, unsigned long nodeIndex,
530  const vector<string> &portIdentifiers, const vector<unsigned long> typeIndexes)
531 {
532  for (size_t j = 0; j < portIdentifiers.size(); ++j)
533  carryOverPortIdentifier(oldCompositionIdentifier, newCompositionIdentifier, portIdentifiers[j], nodeIndex, typeIndexes[j]);
534 }
535 
539 void VuoNodeRegistry::removeCarriedOverPortIdentifier(const char *compositionIdentifier, const string &oldPortIdentifier)
540 {
541  map<string, void *>::const_iterator foundIter;
542  bool found = findCachedInfoForPort<void *>(carriedOverDataForPort, compositionIdentifier, oldPortIdentifier, foundIter);
543  if (! found)
544  {
545  VUserLog("Couldn't find cache for port %s", buildCompositionIdentifier(compositionIdentifier, oldPortIdentifier).c_str());
546  return;
547  }
548 
549  carriedOverDataForPort[compositionIdentifier].erase(oldPortIdentifier);
550  carriedOverNodeIndexForPort[compositionIdentifier].erase(oldPortIdentifier);
551  carriedOverTypeIndexForPort[compositionIdentifier].erase(oldPortIdentifier);
552 
553  if (carriedOverDataForPort[compositionIdentifier].empty())
554  carriedOverDataForPort.erase(compositionIdentifier);
555  if (carriedOverNodeIndexForPort[compositionIdentifier].empty())
556  carriedOverNodeIndexForPort.erase(compositionIdentifier);
557  if (carriedOverTypeIndexForPort[compositionIdentifier].empty())
558  carriedOverTypeIndexForPort.erase(compositionIdentifier);
559 }
560 
566 void VuoNodeRegistry::carryOverPortData(const char *oldCompositionIdentifier, const char *newCompositionIdentifier,
567  const string &oldPortIdentifier, const string &newPortIdentifier, PortContext *newPortContext)
568 {
569  void *carriedOverData;
570  {
571  map<string, void *>::const_iterator foundIter;
572  bool found = findCachedInfoForPort<void *>(carriedOverDataForPort, oldCompositionIdentifier, oldPortIdentifier, foundIter);
573  if (! found)
574  {
575  VUserLog("Couldn't find data for carried-over port %s", buildCompositionIdentifier(oldCompositionIdentifier, oldPortIdentifier).c_str());
576  return;
577  }
578 
579  carriedOverData = foundIter->second;
580  }
581 
582  vuoSetPortContextData(newPortContext, carriedOverData);
583 
584  {
585  map<string, void *>::const_iterator foundIter;
586  bool found = findCachedInfoForPort<void *>(dataForPort, newCompositionIdentifier, newPortIdentifier, foundIter);
587  if (! found)
588  {
589  VUserLog("Couldn't find data for port %s", buildCompositionIdentifier(newCompositionIdentifier, newPortIdentifier).c_str());
590  return;
591  }
592 
593  dataForPort[newCompositionIdentifier][newPortIdentifier] = carriedOverData;
594  }
595 }
596 
603 void VuoNodeRegistry::initContextForTopLevelComposition(VuoCompositionState *compositionState, bool hasInstanceData,
604  unsigned long publishedOutputPortCount)
605 {
606  const char *compositionIdentifier = compositionState->compositionIdentifier;
607 
608  if (persistentState->compositionDiff->isCompositionStartingOrStopping())
609  {
610  // Create and register a node context for the top-level composition.
611  NodeContext *compositionContext = vuoCreateNodeContext(hasInstanceData, true, publishedOutputPortCount);
612  addNodeContext(compositionIdentifier, topLevelCompositionIndex, compositionContext);
613  }
614  else
615  {
616  carryOverNodeContext(compositionIdentifier, compositionIdentifier, topLevelCompositionIndex);
617  }
618 
619  initContextsForCompositionContents(compositionState);
620 }
621 
626 void VuoNodeRegistry::initContextsForCompositionContents(VuoCompositionState *compositionState)
627 {
628  const char *compositionIdentifier = compositionState->compositionIdentifier;
629 
630  for (size_t nodeIndex = 0; nodeIndex < nodeMetadatas[compositionIdentifier].size(); ++nodeIndex)
631  {
632  NodeMetadata nodeMetadata = nodeMetadatas[compositionIdentifier][nodeIndex];
633  NodeContext *nodeContext = NULL;
634 
635  json_object *replacementObj = NULL;
636  VuoCompositionDiff::ChangeType changeType = persistentState->compositionDiff->findNode(compositionIdentifier,
637  nodeMetadata.identifier.c_str(),
638  &replacementObj);
639  if (changeType == VuoCompositionDiff::ChangeStartStop ||
641  {
642  // Create and register a node context for the added node and a port context for each of its ports.
643  NodeContext *nodeContext = nodeMetadata.compositionCreateContextForNode(nodeIndex);
644  addNodeContext(compositionIdentifier, nodeIndex, nodeContext);
645 
646  // Add the added node's ports to the port cache.
647  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
648  {
649  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
650  PortContext *portContext = vuoGetNodeContextPortContext(nodeContext, portIndex);
651  void *portData = vuoGetPortContextData(portContext);
652 
653  addPortIdentifier(compositionIdentifier, portMetadata.identifier, portData, nodeIndex, portMetadata.typeIndex);
654  }
655 
656  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
657  {
658  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
659  PortContext *portContext = vuoGetNodeContextPortContext(nodeContext, portIndex);
660  void *portData = vuoGetPortContextData(portContext);
661 
662  if (portData)
663  {
664  string oldNodeIdentifier;
665  string oldPortIdentifier;
666  if (changeType == VuoCompositionDiff::ChangeReplace &&
667  persistentState->compositionDiff->isPortReplacingAnother(portMetadata.name.c_str(), replacementObj, oldNodeIdentifier, oldPortIdentifier))
668  {
669  // Set the replacement port's data from the port it replaces.
670  carryOverPortData(compositionIdentifier, compositionIdentifier, oldPortIdentifier, portMetadata.identifier, portContext);
671 
672  // Remove the port from the carried-over port info.
673  removeCarriedOverPortIdentifier(compositionIdentifier, oldPortIdentifier);
674  }
675  else
676  {
677  // Set the added port's data to its initial value.
678  nodeMetadata.compositionSetPortValue(compositionState, portMetadata.identifier.c_str(), portMetadata.initialValue.c_str(),
679  false, false, false, false, true);
680  }
681  }
682  }
683  }
684  else
685  {
686  string oldCompositionIdentifier = compositionIdentifier;
687  if (changeType == VuoCompositionDiff::ChangeMove &&
688  (! persistentState->compositionDiff->isNodeBeingMovedToHere(compositionIdentifier, nodeMetadata.identifier.c_str(), replacementObj, oldCompositionIdentifier)))
689  continue;
690 
691  // Restore the kept node's context.
692  nodeContext = carryOverNodeContext(oldCompositionIdentifier.c_str(), compositionIdentifier, nodeIndex);
693 
694  // Restore the kept node's ports to the port cache.
695  vector<string> portIdentifiers;
696  vector<unsigned long> typeIndexes;
697  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
698  {
699  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
700  portIdentifiers.push_back(portMetadata.identifier);
701  typeIndexes.push_back(portMetadata.typeIndex);
702  }
703  carryOverPortIdentifiersForNode(oldCompositionIdentifier.c_str(), compositionIdentifier, nodeMetadata.identifier, nodeIndex, portIdentifiers, typeIndexes);
704 
705  // If the node has been packaged into a subcomposition, copy the port values with connected published input cables
706  // from here (the node inside the subcomposition) to the new subcomposition node in the parent composition.
707  if (changeType == VuoCompositionDiff::ChangeMove)
708  {
709  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
710  {
711  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
712 
713  string destinationCompositionIdentifier;
714  string destinationPortIdentifier;
715  if (persistentState->compositionDiff->isPortBeingCopied(portMetadata.name.c_str(), replacementObj,
716  destinationCompositionIdentifier, destinationPortIdentifier))
717  {
718  char *portValue = getPortValue(compositionState, portMetadata.identifier.c_str(), false);
719 
720  const NodeMetadata *destinationPortMetadata = getNodeMetadataForPort(destinationCompositionIdentifier.c_str(), destinationPortIdentifier.c_str());
721  VuoCompositionState *destinationCompositionState = vuoCreateCompositionState(compositionState->runtimeState, destinationCompositionIdentifier.c_str());
722  destinationPortMetadata->compositionSetPortValue(destinationCompositionState, destinationPortIdentifier.c_str(), portValue, false, false, false, true, true);
723  }
724  }
725  }
726  }
727 
728  json_object_put(replacementObj);
729 
730  // If the node is a subcomposition, initialize the node and port contexts within it.
731  string subcompositionIdentifier = buildCompositionIdentifier(compositionIdentifier, nodeMetadata.identifier);
732  if (nodeMetadatas.find(subcompositionIdentifier) != nodeMetadatas.end())
733  {
734  VuoCompositionState *subcompositionState = vuoCreateCompositionState(compositionState->runtimeState, subcompositionIdentifier.c_str());
735  initContextsForCompositionContents(subcompositionState);
736  vuoFreeCompositionState(subcompositionState);
737  }
738  }
739 }
740 
748 {
749  const char *compositionIdentifier = compositionState->compositionIdentifier;
750 
751  if (persistentState->compositionDiff->isCompositionStartingOrStopping())
752  {
753  // Unregister and destroy the node context for the top-level composition.
754  NodeContext *compositionContext = getNodeContext(compositionIdentifier, topLevelCompositionIndex);
755  removeNodeContext(compositionIdentifier, topLevelCompositionIndex);
756  vuoFreeNodeContext(compositionContext);
757  }
758  else
759  {
760  relocateNodeContext(compositionIdentifier, topLevelCompositionIndex);
761  }
762 
763  finiContextsForCompositionContents(compositionState);
764 
765  nodeMetadatas.clear();
766 }
767 
772 void VuoNodeRegistry::finiContextsForCompositionContents(VuoCompositionState *compositionState)
773 {
774  const char *compositionIdentifier = compositionState->compositionIdentifier;
775 
776  for (size_t nodeIndex = 0; nodeIndex < nodeMetadatas[compositionIdentifier].size(); ++nodeIndex)
777  {
778  NodeMetadata nodeMetadata = nodeMetadatas[compositionIdentifier][nodeIndex];
779 
780  json_object *replacementObj = NULL;
781  VuoCompositionDiff::ChangeType changeType = persistentState->compositionDiff->findNode(compositionIdentifier,
782  nodeMetadata.identifier.c_str(),
783  &replacementObj);
784  if (changeType == VuoCompositionDiff::ChangeStartStop ||
786  {
787  NodeContext *nodeContext = getNodeContext(compositionIdentifier, nodeIndex);
788 
789  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
790  {
791  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
792  PortContext *portContext = vuoGetNodeContextPortContext(nodeContext, portIndex);
793  void *portData = vuoGetPortContextData(portContext);
794 
795  bool relocated = false;
796  if (portData)
797  {
798  if (changeType == VuoCompositionDiff::ChangeReplace &&
799  persistentState->compositionDiff->isPortBeingReplaced(portMetadata.name.c_str(), replacementObj))
800  {
801  // Retain the being-replaced port's data for after the live-coding reload.
802  vuoRetainPortContextData(portContext);
803 
804  // Carry over the port's data
805  relocatePortIdentifier(compositionIdentifier, portMetadata.identifier);
806  relocated = true;
807  }
808  else
809  {
810  // Release the port's data.
811  nodeMetadata.compositionReleasePortData(portData, portMetadata.typeIndex);
812  }
813  }
814 
815  if (! relocated)
816  {
817  // Remove the port from the (non-carried-over) port cache.
818  removePortIdentifier(compositionIdentifier, portMetadata.identifier);
819  }
820  }
821 
822  // Unregister and destroy the node's context.
823  removeNodeContext(compositionIdentifier, nodeIndex);
824  vuoFreeNodeContext(nodeContext);
825  }
826  else
827  {
828  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
829  {
830  // Carry over the port's data
831  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
832  relocatePortIdentifier(compositionIdentifier, portMetadata.identifier);
833  }
834 
835  // Carry over the node's context
836  relocateNodeContext(compositionIdentifier, nodeIndex);
837  }
838 
839  json_object_put(replacementObj);
840 
841  string subcompositionIdentifier = buildCompositionIdentifier(compositionIdentifier, nodeMetadata.identifier);
842  if (nodeMetadatas.find(subcompositionIdentifier) != nodeMetadatas.end())
843  {
844  // Recursive call for subcomposition.
845  VuoCompositionState *subcompositionState = vuoCreateCompositionState(compositionState->runtimeState, subcompositionIdentifier.c_str());
846  finiContextsForCompositionContents(subcompositionState);
847  vuoFreeCompositionState(subcompositionState);
848  }
849  }
850 }
851 
858 void VuoNodeRegistry::setPortValue(VuoCompositionState *compositionState, const char *portIdentifier, const char *valueAsString)
859 {
860  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
861  if (!nm)
862  return;
863 
864  nm->compositionSetPortValue(compositionState, portIdentifier, valueAsString, true, true, true, true, true);
865 }
866 
873 char * VuoNodeRegistry::getPortValue(VuoCompositionState *compositionState, const char *portIdentifier, bool shouldUseInterprocessSerialization)
874 {
875  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
876  if (!nm)
877  return nullptr;
878 
879  return nm->compositionGetPortValue(compositionState, portIdentifier, shouldUseInterprocessSerialization ? 2 : 1, true);
880 }
881 
888 char * VuoNodeRegistry::getPortSummary(VuoCompositionState *compositionState, const char *portIdentifier)
889 {
890  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
891  if (!nm)
892  return nullptr;
893 
894  return nm->compositionGetPortValue(compositionState, portIdentifier, 0, true);
895 }
896 
903 void VuoNodeRegistry::fireTriggerPortEvent(VuoCompositionState *compositionState, const char *portIdentifier)
904 {
905  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
906  if (!nm)
907  return;
908 
909  nm->compositionFireTriggerPortEvent(compositionState, portIdentifier);
910 }
911 
915 void VuoNodeRegistry::print(void)
916 {
917  const char *indent = " ";
918 
919  ostringstream oss;
920  oss << "=== node metadatas ===" << endl << endl;
921  for (map<string, vector<NodeMetadata> >::iterator i = nodeMetadatas.begin(); i != nodeMetadatas.end(); ++i)
922  {
923  oss << indent << i->first << endl;
924  for (size_t j = 0; j < i->second.size(); ++j)
925  oss << indent << indent << j << " " << i->second[j].identifier << ", " << i->second[j].portMetadatas.size() << " ports" << endl;
926  }
927  oss << endl;
928 
929  oss << "=== node contexts ===" << endl << endl;
930  for (map<unsigned long, map<unsigned long, NodeContext *> >::iterator i = nodeContextForIndex.begin(); i != nodeContextForIndex.end(); ++i)
931  {
932  string compositionIdentifier = getCompositionIdentifierForHash(i->first);
933  oss << indent << compositionIdentifier << endl;
934  for (map<unsigned long, NodeContext *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
935  oss << indent << indent << getNodeIdentifierForIndex(compositionIdentifier.c_str(), j->first) << " " << j->second << endl;
936  }
937  oss << endl;
938 
939  oss << "=== carried-over node contexts ===" << endl << endl;
940  for (map<string, map<string, NodeContext *> >::iterator i = carriedOverNodeContextForIdentifier.begin(); i != carriedOverNodeContextForIdentifier.end(); ++i)
941  {
942  oss << indent << i->first << endl;
943  for (map<string, NodeContext *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
944  oss << indent << indent << j->first << " " << j->second << endl;
945  }
946  oss << endl;
947 
948  oss << "=== cached ports ===" << endl << endl;
949  for (map<string, map<string, void *> >::iterator i = dataForPort.begin(); i != dataForPort.end(); ++i)
950  {
951  oss << indent << i->first << endl;
952  for (map<string, void *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
953  oss << indent << indent << j->first << " " << j->second << endl;
954  }
955  oss << endl;
956 
957  oss << "=== carried-over cached ports ===" << endl << endl;
958  for (map<string, map<string, void *> >::iterator i = carriedOverDataForPort.begin(); i != carriedOverDataForPort.end(); ++i)
959  {
960  oss << indent << i->first << endl;
961  for (map<string, void *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
962  oss << indent << indent << j->first << " " << j->second << endl;
963  }
964  oss << endl;
965 
966  VUserLog("\n%s", oss.str().c_str());
967 }
968 
969 extern "C"
970 {
971 
977 void vuoAddNodeMetadata(VuoCompositionState *compositionState, const char *nodeIdentifier,
978  NodeContext *(*compositionCreateContextForNode)(unsigned long),
979  void (*compositionSetPortValue)(VuoCompositionState *, const char *, const char *, bool, bool, bool, bool, bool),
980  char * (*compositionGetPortValue)(VuoCompositionState *, const char *, int, bool),
981  void (*compositionFireTriggerPortEvent)(VuoCompositionState *, const char *),
982  void (*compositionReleasePortData)(void *, unsigned long))
983 {
985  const char *compositionIdentifier = compositionState->compositionIdentifier;
986  runtimeState->persistentState->nodeRegistry->addNodeMetadata(compositionIdentifier, nodeIdentifier,
987  compositionCreateContextForNode, compositionSetPortValue,
988  compositionGetPortValue, compositionFireTriggerPortEvent,
989  compositionReleasePortData);
990 }
991 
995 void vuoAddPortMetadata(VuoCompositionState *compositionState, const char *portIdentifier, const char *portName,
996  unsigned long typeIndex, const char *initialValue)
997 {
999  const char *compositionIdentifier = compositionState->compositionIdentifier;
1000  runtimeState->persistentState->nodeRegistry->addPortMetadata(compositionIdentifier, portIdentifier, portName, typeIndex, initialValue);
1001 }
1002 
1006 NodeContext * vuoGetNodeContext(VuoCompositionState *compositionState, unsigned long nodeIndex)
1007 {
1008  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1009  const char *compositionIdentifier = compositionState->compositionIdentifier;
1010  return runtimeState->persistentState->nodeRegistry->getNodeContext(compositionIdentifier, nodeIndex);
1011 }
1012 
1017 {
1018  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1019  const char *compositionIdentifier = compositionState->compositionIdentifier;
1020  return runtimeState->persistentState->nodeRegistry->getCompositionContext(compositionIdentifier);
1021 }
1022 
1026 void * vuoGetDataForPort(VuoCompositionState *compositionState, const char *portIdentifier)
1027 {
1028  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1029  const char *compositionIdentifier = compositionState->compositionIdentifier;
1030  return runtimeState->persistentState->nodeRegistry->getDataForPort(compositionIdentifier, portIdentifier);
1031 }
1032 
1036 unsigned long vuoGetNodeIndexForPort(VuoCompositionState *compositionState, const char *portIdentifier)
1037 {
1038  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1039  const char *compositionIdentifier = compositionState->compositionIdentifier;
1040  return runtimeState->persistentState->nodeRegistry->getNodeIndexForPort(compositionIdentifier, portIdentifier);
1041 }
1042 
1046 unsigned long vuoGetTypeIndexForPort(VuoCompositionState *compositionState, const char *portIdentifier)
1047 {
1048  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1049  const char *compositionIdentifier = compositionState->compositionIdentifier;
1050  return runtimeState->persistentState->nodeRegistry->getTypeIndexForPort(compositionIdentifier, portIdentifier);
1051 }
1052 
1058 void vuoInitContextForTopLevelComposition(VuoCompositionState *compositionState, bool hasInstanceData, unsigned long publishedOutputPortCount)
1059 {
1060  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1061  return runtimeState->persistentState->nodeRegistry->initContextForTopLevelComposition(compositionState, hasInstanceData, publishedOutputPortCount);
1062 }
1063 
1070 {
1071  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1073 }
1074 
1075 }