Vuo  2.0.0
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 dispatch_semaphore_t VuoNodeRegistry::getNodeSemaphoreForPort(const char *compositionIdentifier, const char *portIdentifier)
383 {
384  map<string, dispatch_semaphore_t>::const_iterator foundIter;
385  bool found = findCachedInfoForPort<dispatch_semaphore_t>(nodeSemaphoreForPort, compositionIdentifier, portIdentifier, foundIter);
386  if (found)
387  return foundIter->second;
388 
389  VUserLog("Couldn't find node semaphore for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
390  return NULL;
391 }
392 
396 unsigned long VuoNodeRegistry::getNodeIndexForPort(const char *compositionIdentifier, const char *portIdentifier)
397 {
398  map<string, unsigned long>::const_iterator foundIter;
399  bool found = findCachedInfoForPort<unsigned long>(nodeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
400  if (found)
401  return foundIter->second;
402 
403  VUserLog("Couldn't find node index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
404  return 0;
405 }
406 
410 unsigned long VuoNodeRegistry::getTypeIndexForPort(const char *compositionIdentifier, const char *portIdentifier)
411 {
412  map<string, unsigned long>::const_iterator foundIter;
413  bool found = findCachedInfoForPort<unsigned long>(typeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
414  if (found)
415  return foundIter->second;
416 
417  VUserLog("Couldn't find type index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
418  return 0;
419 }
420 
424 void VuoNodeRegistry::addPortIdentifier(const char *compositionIdentifier, const string &portIdentifier,
425  void *data, dispatch_semaphore_t nodeSemaphore, unsigned long nodeIndex, unsigned long typeIndex)
426 {
427  map<string, void *>::const_iterator foundIter;
428  bool found = findCachedInfoForPort<void *>(dataForPort, compositionIdentifier, portIdentifier, foundIter);
429  if (found)
430  VUserLog("Cache overwritten for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
431 
432  dataForPort[compositionIdentifier][portIdentifier] = data;
433  nodeSemaphoreForPort[compositionIdentifier][portIdentifier] = nodeSemaphore;
434  nodeIndexForPort[compositionIdentifier][portIdentifier] = nodeIndex;
435  typeIndexForPort[compositionIdentifier][portIdentifier] = typeIndex;
436 }
437 
441 void VuoNodeRegistry::removePortIdentifier(const char *compositionIdentifier, const string &portIdentifier)
442 {
443  {
444  map<string, void *>::const_iterator foundIter;
445  bool found = findCachedInfoForPort<void *>(dataForPort, compositionIdentifier, portIdentifier, foundIter);
446  if (found)
447  {
448  dataForPort[compositionIdentifier].erase(portIdentifier);
449 
450  if (dataForPort[compositionIdentifier].empty())
451  dataForPort.erase(compositionIdentifier);
452  }
453  else
454  VUserLog("Couldn't find data for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
455  }
456  {
457  map<string, dispatch_semaphore_t>::const_iterator foundIter;
458  bool found = findCachedInfoForPort<dispatch_semaphore_t>(nodeSemaphoreForPort, compositionIdentifier, portIdentifier, foundIter);
459  if (found)
460  {
461  nodeSemaphoreForPort[compositionIdentifier].erase(portIdentifier);
462 
463  if (nodeSemaphoreForPort[compositionIdentifier].empty())
464  nodeSemaphoreForPort.erase(compositionIdentifier);
465  }
466  else
467  VUserLog("Couldn't find node semaphore for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
468  }
469  {
470  map<string, unsigned long>::const_iterator foundIter;
471  bool found = findCachedInfoForPort<unsigned long>(nodeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
472  if (found)
473  {
474  nodeIndexForPort[compositionIdentifier].erase(portIdentifier);
475 
476  if (nodeIndexForPort[compositionIdentifier].empty())
477  nodeIndexForPort.erase(compositionIdentifier);
478  }
479  else
480  VUserLog("Couldn't find node index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
481  }
482  {
483  map<string, unsigned long>::const_iterator foundIter;
484  bool found = findCachedInfoForPort<unsigned long>(typeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
485  if (found)
486  {
487  typeIndexForPort[compositionIdentifier].erase(portIdentifier);
488 
489  if (typeIndexForPort[compositionIdentifier].empty())
490  typeIndexForPort.erase(compositionIdentifier);
491  }
492  else
493  VUserLog("Couldn't find type index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
494  }
495 }
496 
500 void VuoNodeRegistry::relocatePortIdentifier(const char *compositionIdentifier, const string &portIdentifier)
501 {
502  {
503  map<string, void *>::const_iterator foundIter;
504  bool found = findCachedInfoForPort<void *>(dataForPort, compositionIdentifier, portIdentifier, foundIter);
505  if (found)
506  carriedOverDataForPort[compositionIdentifier][portIdentifier] = foundIter->second;
507  else
508  VUserLog("Couldn't find data for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
509  }
510  {
511  map<string, dispatch_semaphore_t>::const_iterator foundIter;
512  bool found = findCachedInfoForPort<dispatch_semaphore_t>(nodeSemaphoreForPort, compositionIdentifier, portIdentifier, foundIter);
513  if (found)
514  carriedOverNodeSemaphoreForPort[compositionIdentifier][portIdentifier] = foundIter->second;
515  else
516  VUserLog("Couldn't find node semaphore for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
517  }
518  {
519  map<string, unsigned long>::const_iterator foundIter;
520  bool found = findCachedInfoForPort<unsigned long>(nodeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
521  if (found)
522  carriedOverNodeIndexForPort[compositionIdentifier][portIdentifier] = foundIter->second;
523  else
524  VUserLog("Couldn't find node index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
525  }
526  {
527  map<string, unsigned long>::const_iterator foundIter;
528  bool found = findCachedInfoForPort<unsigned long>(typeIndexForPort, compositionIdentifier, portIdentifier, foundIter);
529  if (found)
530  carriedOverTypeIndexForPort[compositionIdentifier][portIdentifier] = foundIter->second;
531  else
532  VUserLog("Couldn't find type index for port %s", buildCompositionIdentifier(compositionIdentifier, portIdentifier).c_str());
533  }
534 
535  removePortIdentifier(compositionIdentifier, portIdentifier);
536 }
537 
542 void VuoNodeRegistry::carryOverPortIdentifier(const char *oldCompositionIdentifier, const char *newCompositionIdentifier,
543  const string &portIdentifier, unsigned long nodeIndex, unsigned long typeIndex)
544 {
545  map<string, void *>::const_iterator foundIter;
546  bool found = findCachedInfoForPort<void *>(carriedOverDataForPort, oldCompositionIdentifier, portIdentifier, foundIter);
547  if (! found)
548  {
549  VUserLog("Couldn't find cache for port %s", buildCompositionIdentifier(oldCompositionIdentifier, portIdentifier).c_str());
550  return;
551  }
552 
553  dataForPort[newCompositionIdentifier][portIdentifier] = carriedOverDataForPort[oldCompositionIdentifier][portIdentifier];
554  nodeSemaphoreForPort[newCompositionIdentifier][portIdentifier] = carriedOverNodeSemaphoreForPort[oldCompositionIdentifier][portIdentifier];
555  nodeIndexForPort[newCompositionIdentifier][portIdentifier] = nodeIndex;
556  typeIndexForPort[newCompositionIdentifier][portIdentifier] = typeIndex;
557 
558  removeCarriedOverPortIdentifier(oldCompositionIdentifier, portIdentifier);
559 }
560 
565 void VuoNodeRegistry::carryOverPortIdentifiersForNode(const char *oldCompositionIdentifier, const char *newCompositionIdentifier,
566  const string &nodeIdentifier, unsigned long nodeIndex,
567  const vector<string> &portIdentifiers, const vector<unsigned long> typeIndexes)
568 {
569  for (size_t j = 0; j < portIdentifiers.size(); ++j)
570  carryOverPortIdentifier(oldCompositionIdentifier, newCompositionIdentifier, portIdentifiers[j], nodeIndex, typeIndexes[j]);
571 }
572 
576 void VuoNodeRegistry::removeCarriedOverPortIdentifier(const char *compositionIdentifier, const string &oldPortIdentifier)
577 {
578  map<string, void *>::const_iterator foundIter;
579  bool found = findCachedInfoForPort<void *>(carriedOverDataForPort, compositionIdentifier, oldPortIdentifier, foundIter);
580  if (! found)
581  {
582  VUserLog("Couldn't find cache for port %s", buildCompositionIdentifier(compositionIdentifier, oldPortIdentifier).c_str());
583  return;
584  }
585 
586  carriedOverDataForPort[compositionIdentifier].erase(oldPortIdentifier);
587  carriedOverNodeSemaphoreForPort[compositionIdentifier].erase(oldPortIdentifier);
588  carriedOverNodeIndexForPort[compositionIdentifier].erase(oldPortIdentifier);
589  carriedOverTypeIndexForPort[compositionIdentifier].erase(oldPortIdentifier);
590 
591  if (carriedOverDataForPort[compositionIdentifier].empty())
592  carriedOverDataForPort.erase(compositionIdentifier);
593  if (carriedOverNodeSemaphoreForPort[compositionIdentifier].empty())
594  carriedOverNodeSemaphoreForPort.erase(compositionIdentifier);
595  if (carriedOverNodeIndexForPort[compositionIdentifier].empty())
596  carriedOverNodeIndexForPort.erase(compositionIdentifier);
597  if (carriedOverTypeIndexForPort[compositionIdentifier].empty())
598  carriedOverTypeIndexForPort.erase(compositionIdentifier);
599 }
600 
606 void VuoNodeRegistry::carryOverPortData(const char *oldCompositionIdentifier, const char *newCompositionIdentifier,
607  const string &oldPortIdentifier, const string &newPortIdentifier, PortContext *newPortContext)
608 {
609  void *carriedOverData;
610  {
611  map<string, void *>::const_iterator foundIter;
612  bool found = findCachedInfoForPort<void *>(carriedOverDataForPort, oldCompositionIdentifier, oldPortIdentifier, foundIter);
613  if (! found)
614  {
615  VUserLog("Couldn't find data for carried-over port %s", buildCompositionIdentifier(oldCompositionIdentifier, oldPortIdentifier).c_str());
616  return;
617  }
618 
619  carriedOverData = foundIter->second;
620  }
621 
622  vuoSetPortContextData(newPortContext, carriedOverData);
623 
624  {
625  map<string, void *>::const_iterator foundIter;
626  bool found = findCachedInfoForPort<void *>(dataForPort, newCompositionIdentifier, newPortIdentifier, foundIter);
627  if (! found)
628  {
629  VUserLog("Couldn't find data for port %s", buildCompositionIdentifier(newCompositionIdentifier, newPortIdentifier).c_str());
630  return;
631  }
632 
633  dataForPort[newCompositionIdentifier][newPortIdentifier] = carriedOverData;
634  }
635 }
636 
643 void VuoNodeRegistry::initContextForTopLevelComposition(VuoCompositionState *compositionState, bool hasInstanceData,
644  unsigned long publishedOutputPortCount)
645 {
646  const char *compositionIdentifier = compositionState->compositionIdentifier;
647 
648  if (persistentState->compositionDiff->isCompositionStartingOrStopping())
649  {
650  // Create and register a node context for the top-level composition.
651  NodeContext *compositionContext = vuoCreateNodeContext(hasInstanceData, true, publishedOutputPortCount);
652  addNodeContext(compositionIdentifier, topLevelCompositionIndex, compositionContext);
653  }
654  else
655  {
656  carryOverNodeContext(compositionIdentifier, compositionIdentifier, topLevelCompositionIndex);
657  }
658 
659  initContextsForCompositionContents(compositionState);
660 }
661 
666 void VuoNodeRegistry::initContextsForCompositionContents(VuoCompositionState *compositionState)
667 {
668  const char *compositionIdentifier = compositionState->compositionIdentifier;
669 
670  for (size_t nodeIndex = 0; nodeIndex < nodeMetadatas[compositionIdentifier].size(); ++nodeIndex)
671  {
672  NodeMetadata nodeMetadata = nodeMetadatas[compositionIdentifier][nodeIndex];
673  NodeContext *nodeContext = NULL;
674 
675  json_object *replacementObj = NULL;
676  VuoCompositionDiff::ChangeType changeType = persistentState->compositionDiff->findNode(compositionIdentifier,
677  nodeMetadata.identifier.c_str(),
678  &replacementObj);
679  if (changeType == VuoCompositionDiff::ChangeStartStop ||
681  {
682  // Create and register a node context for the added node and a port context for each of its ports.
683  NodeContext *nodeContext = nodeMetadata.compositionCreateContextForNode(nodeIndex);
684  addNodeContext(compositionIdentifier, nodeIndex, nodeContext);
685 
686  // Add the added node's ports to the port cache.
687  dispatch_semaphore_t nodeSemaphore = vuoGetNodeContextSemaphore(nodeContext);
688  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
689  {
690  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
691  PortContext *portContext = vuoGetNodeContextPortContext(nodeContext, portIndex);
692  void *portData = vuoGetPortContextData(portContext);
693 
694  addPortIdentifier(compositionIdentifier, portMetadata.identifier, portData, nodeSemaphore, nodeIndex, portMetadata.typeIndex);
695  }
696 
697  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
698  {
699  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
700  PortContext *portContext = vuoGetNodeContextPortContext(nodeContext, portIndex);
701  void *portData = vuoGetPortContextData(portContext);
702 
703  if (portData)
704  {
705  string oldNodeIdentifier;
706  string oldPortIdentifier;
707  if (changeType == VuoCompositionDiff::ChangeReplace &&
708  persistentState->compositionDiff->isPortReplacingAnother(portMetadata.name.c_str(), replacementObj, oldNodeIdentifier, oldPortIdentifier))
709  {
710  // Set the replacement port's data from the port it replaces.
711  carryOverPortData(compositionIdentifier, compositionIdentifier, oldPortIdentifier, portMetadata.identifier, portContext);
712 
713  // Remove the port from the carried-over port info.
714  removeCarriedOverPortIdentifier(compositionIdentifier, oldPortIdentifier);
715  }
716  else
717  {
718  // Set the added port's data to its initial value.
719  nodeMetadata.compositionSetPortValue(compositionState, portMetadata.identifier.c_str(), portMetadata.initialValue.c_str(),
720  false, false, false, false, true);
721  }
722  }
723  }
724  }
725  else
726  {
727  string oldCompositionIdentifier = compositionIdentifier;
728  if (changeType == VuoCompositionDiff::ChangeMove &&
729  (! persistentState->compositionDiff->isNodeBeingMovedToHere(compositionIdentifier, nodeMetadata.identifier.c_str(), replacementObj, oldCompositionIdentifier)))
730  continue;
731 
732  // Restore the kept node's context.
733  nodeContext = carryOverNodeContext(oldCompositionIdentifier.c_str(), compositionIdentifier, nodeIndex);
734 
735  // Restore the kept node's ports to the port cache.
736  vector<string> portIdentifiers;
737  vector<unsigned long> typeIndexes;
738  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
739  {
740  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
741  portIdentifiers.push_back(portMetadata.identifier);
742  typeIndexes.push_back(portMetadata.typeIndex);
743  }
744  carryOverPortIdentifiersForNode(oldCompositionIdentifier.c_str(), compositionIdentifier, nodeMetadata.identifier, nodeIndex, portIdentifiers, typeIndexes);
745 
746  // If the node has been packaged into a subcomposition, copy the port values with connected published input cables
747  // from here (the node inside the subcomposition) to the new subcomposition node in the parent composition.
748  if (changeType == VuoCompositionDiff::ChangeMove)
749  {
750  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
751  {
752  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
753 
754  string destinationCompositionIdentifier;
755  string destinationPortIdentifier;
756  if (persistentState->compositionDiff->isPortBeingCopied(portMetadata.name.c_str(), replacementObj,
757  destinationCompositionIdentifier, destinationPortIdentifier))
758  {
759  char *portValue = getPortValue(compositionState, portMetadata.identifier.c_str(), false);
760 
761  const NodeMetadata *destinationPortMetadata = getNodeMetadataForPort(destinationCompositionIdentifier.c_str(), destinationPortIdentifier.c_str());
762  VuoCompositionState *destinationCompositionState = vuoCreateCompositionState(compositionState->runtimeState, destinationCompositionIdentifier.c_str());
763  destinationPortMetadata->compositionSetPortValue(destinationCompositionState, destinationPortIdentifier.c_str(), portValue, false, false, false, true, true);
764  }
765  }
766  }
767  }
768 
769  json_object_put(replacementObj);
770 
771  // If the node is a subcomposition, initialize the node and port contexts within it.
772  string subcompositionIdentifier = buildCompositionIdentifier(compositionIdentifier, nodeMetadata.identifier);
773  if (nodeMetadatas.find(subcompositionIdentifier) != nodeMetadatas.end())
774  {
775  VuoCompositionState *subcompositionState = vuoCreateCompositionState(compositionState->runtimeState, subcompositionIdentifier.c_str());
776  initContextsForCompositionContents(subcompositionState);
777  vuoFreeCompositionState(subcompositionState);
778  }
779  }
780 }
781 
789 {
790  const char *compositionIdentifier = compositionState->compositionIdentifier;
791 
792  if (persistentState->compositionDiff->isCompositionStartingOrStopping())
793  {
794  // Unregister and destroy the node context for the top-level composition.
795  NodeContext *compositionContext = getNodeContext(compositionIdentifier, topLevelCompositionIndex);
796  removeNodeContext(compositionIdentifier, topLevelCompositionIndex);
797  vuoFreeNodeContext(compositionContext);
798  }
799  else
800  {
801  relocateNodeContext(compositionIdentifier, topLevelCompositionIndex);
802  }
803 
804  finiContextsForCompositionContents(compositionState);
805 
806  nodeMetadatas.clear();
807 }
808 
813 void VuoNodeRegistry::finiContextsForCompositionContents(VuoCompositionState *compositionState)
814 {
815  const char *compositionIdentifier = compositionState->compositionIdentifier;
816 
817  for (size_t nodeIndex = 0; nodeIndex < nodeMetadatas[compositionIdentifier].size(); ++nodeIndex)
818  {
819  NodeMetadata nodeMetadata = nodeMetadatas[compositionIdentifier][nodeIndex];
820 
821  json_object *replacementObj = NULL;
822  VuoCompositionDiff::ChangeType changeType = persistentState->compositionDiff->findNode(compositionIdentifier,
823  nodeMetadata.identifier.c_str(),
824  &replacementObj);
825  if (changeType == VuoCompositionDiff::ChangeStartStop ||
827  {
828  NodeContext *nodeContext = getNodeContext(compositionIdentifier, nodeIndex);
829 
830  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
831  {
832  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
833  PortContext *portContext = vuoGetNodeContextPortContext(nodeContext, portIndex);
834  void *portData = vuoGetPortContextData(portContext);
835 
836  bool relocated = false;
837  if (portData)
838  {
839  if (changeType == VuoCompositionDiff::ChangeReplace &&
840  persistentState->compositionDiff->isPortBeingReplaced(portMetadata.name.c_str(), replacementObj))
841  {
842  // Retain the being-replaced port's data for after the live-coding reload.
843  vuoRetainPortContextData(portContext);
844 
845  // Carry over the port's data
846  relocatePortIdentifier(compositionIdentifier, portMetadata.identifier);
847  relocated = true;
848  }
849  else
850  {
851  // Release the port's data.
852  nodeMetadata.compositionReleasePortData(portData, portMetadata.typeIndex);
853  }
854  }
855 
856  if (! relocated)
857  {
858  // Remove the port from the (non-carried-over) port cache.
859  removePortIdentifier(compositionIdentifier, portMetadata.identifier);
860  }
861  }
862 
863  // Unregister and destroy the node's context.
864  removeNodeContext(compositionIdentifier, nodeIndex);
865  vuoFreeNodeContext(nodeContext);
866  }
867  else
868  {
869  for (size_t portIndex = 0; portIndex < nodeMetadata.portMetadatas.size(); ++portIndex)
870  {
871  // Carry over the port's data
872  PortMetadata portMetadata = nodeMetadata.portMetadatas[portIndex];
873  relocatePortIdentifier(compositionIdentifier, portMetadata.identifier);
874  }
875 
876  // Carry over the node's context
877  relocateNodeContext(compositionIdentifier, nodeIndex);
878  }
879 
880  json_object_put(replacementObj);
881 
882  string subcompositionIdentifier = buildCompositionIdentifier(compositionIdentifier, nodeMetadata.identifier);
883  if (nodeMetadatas.find(subcompositionIdentifier) != nodeMetadatas.end())
884  {
885  // Recursive call for subcomposition.
886  VuoCompositionState *subcompositionState = vuoCreateCompositionState(compositionState->runtimeState, subcompositionIdentifier.c_str());
887  finiContextsForCompositionContents(subcompositionState);
888  vuoFreeCompositionState(subcompositionState);
889  }
890  }
891 }
892 
899 void VuoNodeRegistry::setPortValue(VuoCompositionState *compositionState, const char *portIdentifier, const char *valueAsString)
900 {
901  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
902  if (!nm)
903  return;
904 
905  nm->compositionSetPortValue(compositionState, portIdentifier, valueAsString, true, true, true, true, true);
906 }
907 
914 char * VuoNodeRegistry::getPortValue(VuoCompositionState *compositionState, const char *portIdentifier, bool shouldUseInterprocessSerialization)
915 {
916  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
917  if (!nm)
918  return nullptr;
919 
920  return nm->compositionGetPortValue(compositionState, portIdentifier, shouldUseInterprocessSerialization ? 2 : 1, true);
921 }
922 
929 char * VuoNodeRegistry::getPortSummary(VuoCompositionState *compositionState, const char *portIdentifier)
930 {
931  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
932  if (!nm)
933  return nullptr;
934 
935  return nm->compositionGetPortValue(compositionState, portIdentifier, 0, true);
936 }
937 
944 void VuoNodeRegistry::fireTriggerPortEvent(VuoCompositionState *compositionState, const char *portIdentifier)
945 {
946  const NodeMetadata *nm = getNodeMetadataForPort(compositionState->compositionIdentifier, portIdentifier);
947  if (!nm)
948  return;
949 
950  nm->compositionFireTriggerPortEvent(compositionState, portIdentifier);
951 }
952 
956 void VuoNodeRegistry::print(void)
957 {
958  const char *indent = " ";
959 
960  printf("=== node metadatas ===\n\n");
961  for (map<string, vector<NodeMetadata> >::iterator i = nodeMetadatas.begin(); i != nodeMetadatas.end(); ++i)
962  {
963  printf("%s%s\n", indent, i->first.c_str());
964  for (size_t j = 0; j < i->second.size(); ++j)
965  printf("%s%s%lu %s, %lu ports\n", indent, indent, j, i->second[j].identifier.c_str(), i->second[j].portMetadatas.size());
966  }
967  printf("\n");
968 
969  printf("=== node contexts ===\n\n");
970  for (map<unsigned long, map<unsigned long, NodeContext *> >::iterator i = nodeContextForIndex.begin(); i != nodeContextForIndex.end(); ++i)
971  {
972  string compositionIdentifier = getCompositionIdentifierForHash(i->first);
973  printf("%s%s\n", indent, compositionIdentifier.c_str());
974  for (map<unsigned long, NodeContext *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
975  printf("%s%s%s %p\n", indent, indent, getNodeIdentifierForIndex(compositionIdentifier.c_str(), j->first).c_str(), j->second);
976  }
977  printf("\n");
978 
979  printf("=== carried-over node contexts ===\n\n");
980  for (map<string, map<string, NodeContext *> >::iterator i = carriedOverNodeContextForIdentifier.begin(); i != carriedOverNodeContextForIdentifier.end(); ++i)
981  {
982  printf("%s%s\n", indent, i->first.c_str());
983  for (map<string, NodeContext *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
984  printf("%s%s%s %p\n", indent, indent, j->first.c_str(), j->second);
985  }
986  printf("\n");
987 
988  printf("=== cached ports ===\n\n");
989  for (map<string, map<string, void *> >::iterator i = dataForPort.begin(); i != dataForPort.end(); ++i)
990  {
991  printf("%s%s\n", indent, i->first.c_str());
992  for (map<string, void *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
993  printf("%s%s%s %p\n", indent, indent, j->first.c_str(), j->second);
994  }
995  printf("\n");
996 
997  printf("=== carried-over cached ports ===\n\n");
998  for (map<string, map<string, void *> >::iterator i = carriedOverDataForPort.begin(); i != carriedOverDataForPort.end(); ++i)
999  {
1000  printf("%s%s\n", indent, i->first.c_str());
1001  for (map<string, void *>::iterator j = i->second.begin(); j != i->second.end(); ++j)
1002  printf("%s%s%s %p\n", indent, indent, j->first.c_str(), j->second);
1003  }
1004  printf("\n");
1005 }
1006 
1007 extern "C"
1008 {
1009 
1015 void vuoAddNodeMetadata(VuoCompositionState *compositionState, const char *nodeIdentifier,
1016  NodeContext *(*compositionCreateContextForNode)(unsigned long),
1017  void (*compositionSetPortValue)(VuoCompositionState *, const char *, const char *, bool, bool, bool, bool, bool),
1018  char * (*compositionGetPortValue)(VuoCompositionState *, const char *, int, bool),
1019  void (*compositionFireTriggerPortEvent)(VuoCompositionState *, const char *),
1020  void (*compositionReleasePortData)(void *, unsigned long))
1021 {
1022  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1023  const char *compositionIdentifier = compositionState->compositionIdentifier;
1024  runtimeState->persistentState->nodeRegistry->addNodeMetadata(compositionIdentifier, nodeIdentifier,
1025  compositionCreateContextForNode, compositionSetPortValue,
1026  compositionGetPortValue, compositionFireTriggerPortEvent,
1027  compositionReleasePortData);
1028 }
1029 
1033 void vuoAddPortMetadata(VuoCompositionState *compositionState, const char *portIdentifier, const char *portName,
1034  unsigned long typeIndex, const char *initialValue)
1035 {
1036  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1037  const char *compositionIdentifier = compositionState->compositionIdentifier;
1038  runtimeState->persistentState->nodeRegistry->addPortMetadata(compositionIdentifier, portIdentifier, portName, typeIndex, initialValue);
1039 }
1040 
1044 NodeContext * vuoGetNodeContext(VuoCompositionState *compositionState, unsigned long nodeIndex)
1045 {
1046  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1047  const char *compositionIdentifier = compositionState->compositionIdentifier;
1048  return runtimeState->persistentState->nodeRegistry->getNodeContext(compositionIdentifier, nodeIndex);
1049 }
1050 
1055 {
1056  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1057  const char *compositionIdentifier = compositionState->compositionIdentifier;
1058  return runtimeState->persistentState->nodeRegistry->getCompositionContext(compositionIdentifier);
1059 }
1060 
1064 void * vuoGetDataForPort(VuoCompositionState *compositionState, const char *portIdentifier)
1065 {
1066  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1067  const char *compositionIdentifier = compositionState->compositionIdentifier;
1068  return runtimeState->persistentState->nodeRegistry->getDataForPort(compositionIdentifier, portIdentifier);
1069 }
1070 
1074 dispatch_semaphore_t vuoGetNodeSemaphoreForPort(VuoCompositionState *compositionState, const char *portIdentifier)
1075 {
1076  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1077  const char *compositionIdentifier = compositionState->compositionIdentifier;
1078  return runtimeState->persistentState->nodeRegistry->getNodeSemaphoreForPort(compositionIdentifier, portIdentifier);
1079 }
1080 
1084 unsigned long vuoGetNodeIndexForPort(VuoCompositionState *compositionState, const char *portIdentifier)
1085 {
1086  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1087  const char *compositionIdentifier = compositionState->compositionIdentifier;
1088  return runtimeState->persistentState->nodeRegistry->getNodeIndexForPort(compositionIdentifier, portIdentifier);
1089 }
1090 
1094 unsigned long vuoGetTypeIndexForPort(VuoCompositionState *compositionState, const char *portIdentifier)
1095 {
1096  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1097  const char *compositionIdentifier = compositionState->compositionIdentifier;
1098  return runtimeState->persistentState->nodeRegistry->getTypeIndexForPort(compositionIdentifier, portIdentifier);
1099 }
1100 
1106 void vuoInitContextForTopLevelComposition(VuoCompositionState *compositionState, bool hasInstanceData, unsigned long publishedOutputPortCount)
1107 {
1108  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1109  return runtimeState->persistentState->nodeRegistry->initContextForTopLevelComposition(compositionState, hasInstanceData, publishedOutputPortCount);
1110 }
1111 
1118 {
1119  VuoRuntimeState *runtimeState = (VuoRuntimeState *)compositionState->runtimeState;
1121 }
1122 
1123 }