Vuo  2.3.1
VuoCompilerMakeListNodeClass.cc
Go to the documentation of this file.
1 
10 #include <sstream>
11 
12 #include "VuoGenericType.hh"
13 #include "VuoStringUtilities.hh"
14 
15 #include "VuoCompiler.hh"
24 #include "VuoCompilerPort.hh"
25 #include "VuoNodeClass.hh"
26 #include "VuoPort.hh"
27 
28 
30 const string VuoCompilerMakeListNodeClass::makeListNodeClassNamePrefix = "vuo.list.make.";
31 
33 const string VuoCompilerMakeListNodeClass::makeListNodeClassDescription = "Creates a list from the given items.";
34 
35 
39 VuoCompilerMakeListNodeClass::VuoCompilerMakeListNodeClass(string nodeClassName, Module *module) :
40  VuoCompilerSpecializedNodeClass(nodeClassName, module)
41 {
42  initialize();
43 }
44 
48 VuoCompilerMakeListNodeClass::VuoCompilerMakeListNodeClass(VuoCompilerMakeListNodeClass *compilerNodeClass) :
49  VuoCompilerSpecializedNodeClass(compilerNodeClass)
50 {
51  initialize();
52 }
53 
57 VuoCompilerMakeListNodeClass::VuoCompilerMakeListNodeClass(VuoNodeClass *baseNodeClass) :
58  VuoCompilerSpecializedNodeClass(baseNodeClass)
59 {
60  initialize();
61 }
62 
66 void VuoCompilerMakeListNodeClass::initialize(void)
67 {
68  itemCount = 0;
69  listType = NULL;
70 }
71 
81 VuoNodeClass * VuoCompilerMakeListNodeClass::newNodeClass(string nodeClassName, VuoCompiler *compiler, dispatch_queue_t llvmQueue)
82 {
83  unsigned long itemCount;
84  string itemTypeStr;
85  bool parsedOk = parseNodeClassName(nodeClassName, itemCount, itemTypeStr);
86  if (! parsedOk)
87  return NULL;
88 
89  VuoCompilerType *itemType = compiler->getType(itemTypeStr);
90  VuoCompilerType *listType = compiler->getType(VuoType::listTypeNamePrefix + itemTypeStr);
91  if (! itemType || ! listType)
92  return NULL;
93 
94  __block VuoCompilerMakeListNodeClass *nodeClass;
95 
96  if (! dynamic_cast<VuoGenericType *>(itemType->getBase()))
97  {
98  // The generic port types have been specialized, so generate LLVM bitcode for the node class.
99 
100  dispatch_sync(llvmQueue, ^{
101 
102  vector<Type *> itemParamTypes = itemType->getFunctionParameterTypes();
103  AttributeList itemFunctionAttributes = itemType->getFunctionAttributes();
104 
105  Module *module = new Module("", *VuoCompiler::globalLLVMContext);
106 
107  // VuoModuleMetadata({});
109 
110 
111  // void nodeEvent
112  // (
113  // VuoInputData(<item type>,<default value>) item1,
114  // ...,
115  // VuoInputData(<item type>,<default value>) item<item count>,
116  // VuoOutputData(VuoList_<item type>) list
117  // )
118 
119  vector<VuoPort *> modelInputPorts;
120  for (unsigned long i = 0; i < itemCount; ++i)
121  {
122  ostringstream oss;
123  oss << i+1;
124  string portName = oss.str();
125 
126  VuoCompilerInputEventPortClass *modelItemPortClass = new VuoCompilerInputEventPortClass(portName);
128  dataClass->setVuoType( itemType->getBase() );
129  modelItemPortClass->setDataClass(dataClass);
130  VuoCompilerPort *modelItemPort = modelItemPortClass->newPort();
131 
132  modelInputPorts.push_back( modelItemPort->getBase() );
133  }
134 
135  VuoCompilerOutputEventPortClass *modelListPortClass = new VuoCompilerOutputEventPortClass("list");
137  dataClass->setVuoType( listType->getBase() );
138  modelListPortClass->setDataClass(dataClass);
139  VuoCompilerPort *modelListPort = modelListPortClass->newPort();
140  vector<VuoPort *> modelOutputPorts( 1, modelListPort->getBase() );
141  map<VuoPort *, size_t> indexOfParameter;
142  map<VuoPort *, size_t> indexOfEventParameter;
143  VuoCompilerConstantsCache constantsCache(module);
144 
145  Function *eventFunction = VuoCompilerCodeGenUtilities::getNodeEventFunction(module, "", false, false,
146  nullptr, modelInputPorts, modelOutputPorts,
147  map<VuoPort *, json_object *>(), map<VuoPort *, string>(),
148  map<VuoPort *, string>(), map<VuoPort *, VuoPortClass::EventBlocking>(),
149  indexOfParameter, indexOfEventParameter, &constantsCache);
150 
151 
152  // {
153  // *list = VuoListCreate_<item type>();
154  // VuoListAppendValue_<item type>(*list, item1);
155  // ...
156  // VuoListAppendValue_<item type>(*list, item<item count>);
157  // }
158 
159  BasicBlock *block = &(eventFunction->getEntryBlock());
160 
161  string itemBackingTypeName;
162  if (VuoGenericType::isGenericTypeName(itemTypeStr))
163  {
164  itemBackingTypeName = VuoCompilerGenericType::chooseBackingTypeName(itemTypeStr, vector<string>());
165  }
166  else
167  {
168  itemBackingTypeName = itemTypeStr;
169  }
170 
171  string listCreateFunctionName = "VuoListCreate_" + itemBackingTypeName;
172  Function *listCreateFunctionSrc = listType->getModule()->getFunction(listCreateFunctionName);
173  Function *listCreateFunction = declareFunctionInModule(module, listCreateFunctionSrc);
174 
175  string listAppendFunctionName = "VuoListAppendValue_" + itemBackingTypeName;
176  Function *listAppendFunctionSrc = listType->getModule()->getFunction(listAppendFunctionName);
177  Function *listAppendFunction = declareFunctionInModule(module, listAppendFunctionSrc);
178 
179  vector<Value *> itemValues;
180  for (VuoPort *itemPort : modelInputPorts)
181  {
182  size_t argIndex = indexOfParameter[itemPort];
183  Value *itemValue = VuoCompilerCodeGenUtilities::getArgumentAtIndex(eventFunction, argIndex);
184  itemValues.push_back(itemValue);
185  if (itemParamTypes.size() > 1)
186  {
187  Value *itemSecondValue = VuoCompilerCodeGenUtilities::getArgumentAtIndex(eventFunction, argIndex + 1);
188  itemValues.push_back(itemSecondValue);
189  }
190  }
191  size_t listArgIndex = indexOfParameter[modelListPort->getBase()];
192  Value *listArg = VuoCompilerCodeGenUtilities::getArgumentAtIndex(eventFunction, listArgIndex);
193 
194  CallInst *listValue = CallInst::Create(listCreateFunction, "", block);
195  Value *listPointer = VuoCompilerCodeGenUtilities::generatePointerToValue(block, listValue);
196  VuoCompilerCodeGenUtilities::generateMemoryCopy(module, block, listPointer, listArg, listType->getSize(module));
197 
198  for (unsigned long i = 0; i < itemCount; ++i)
199  {
200  vector<Value *> listAppendArgs;
201  listAppendArgs.push_back(listValue);
202 
203  int itemValuesIndex = (itemParamTypes.size() > 1 ? 2*i : i);
204 
205  Value *itemArg = itemValues[itemValuesIndex];
206 
207  if (VuoCompilerCodeGenUtilities::isPointerToStruct(itemArg->getType()))
208  itemArg = new BitCastInst(itemArg, listAppendFunction->getFunctionType()->getParamType(1), "", block);
209 
210  listAppendArgs.push_back(itemArg);
211 
212  if (itemParamTypes.size() > 1)
213  listAppendArgs.push_back(itemValues[itemValuesIndex + 1]);
214 
215  CallInst *call = CallInst::Create(listAppendFunction, listAppendArgs, "", block);
216 
217  VuoCompilerCodeGenUtilities::copyParameterAttributes(module, itemFunctionAttributes, 0, listAppendArgs.size()-1, call, 1);
218  }
219 
220  ReturnInst::Create(module->getContext(), block);
221 
222 
223  for (vector<VuoPort *>::iterator i = modelInputPorts.begin(); i != modelInputPorts.end(); ++i)
224  {
225  delete (*i)->getClass()->getCompiler();
226  delete *i;
227  }
228  delete modelListPort;
229  delete modelListPortClass;
230 
231 
232  VuoCompilerMakeListNodeClass *dummyNodeClass = new VuoCompilerMakeListNodeClass(nodeClassName, module);
233 
234  // Reconstruct, this time with a base VuoNodeClass containing actual (non-dummy) ports.
235  nodeClass = new VuoCompilerMakeListNodeClass(dummyNodeClass);
236  delete dummyNodeClass;
237  });
238  }
239  else
240  {
241  // The generic ports have not been specialized, so construct a node class that doesn't yet have an implementation.
242 
243  VuoPortClass *refreshPortClass = (new VuoCompilerInputEventPortClass("refresh"))->getBase();
244 
245  vector<VuoPortClass *> inputPortClasses;
246  inputPortClasses.push_back(refreshPortClass);
247  for (int i = 1; i <= itemCount; ++i)
248  {
249  ostringstream oss;
250  oss << i;
253  portClass->setDataClass(dataClass);
254  portClass->setDataVuoType(itemType->getBase());
255  inputPortClasses.push_back(portClass->getBase());
256  }
257 
258  vector<VuoPortClass *> outputPortClasses;
259  {
262  portClass->setDataClass(dataClass);
263  portClass->setDataVuoType(listType->getBase());
264  outputPortClasses.push_back(portClass->getBase());
265  }
266 
267  VuoNodeClass *baseNodeClass = new VuoNodeClass(nodeClassName, refreshPortClass, inputPortClasses, outputPortClasses);
268  nodeClass = new VuoCompilerMakeListNodeClass(baseNodeClass);
269  }
270 
271  nodeClass->itemCount = itemCount;
272  nodeClass->listType = listType;
273  nodeClass->specializedForGenericTypeName[ VuoGenericType::createGenericTypeName(1) ] = itemTypeStr;
274 
275  nodeClass->getBase()->setDefaultTitle("Make List");
276  nodeClass->getBase()->setDescription(makeListNodeClassDescription);
277  nodeClass->getBase()->setVersion("2.0.0");
278 
279  return nodeClass->getBase();
280 }
281 
287 {
288  return VuoStringUtilities::beginsWith(nodeClassName, makeListNodeClassNamePrefix);
289 }
290 
295 string VuoCompilerMakeListNodeClass::getNodeClassName(unsigned long itemCount, VuoCompilerType *listType)
296 {
298  return buildNodeClassName(itemCount, itemTypeStr);
299 }
300 
306 bool VuoCompilerMakeListNodeClass::parseNodeClassName(string nodeClassName, unsigned long &itemCount, string &itemTypeName)
307 {
308  string itemCountAndType = VuoStringUtilities::substrAfter(nodeClassName, makeListNodeClassNamePrefix);
309  size_t dotPos = itemCountAndType.find(".");
310  if (dotPos == string::npos || dotPos == 0 || dotPos == itemCountAndType.length() - 1)
311  return false;
312 
313  string itemCountStr = itemCountAndType.substr(0, dotPos);
314  itemCount = atol(itemCountStr.c_str());
315  itemTypeName = itemCountAndType.substr(dotPos + 1);
316  return true;
317 }
318 
322 string VuoCompilerMakeListNodeClass::buildNodeClassName(unsigned long itemCount, string itemTypeName)
323 {
324  ostringstream oss;
325  oss << itemCount;
326  string itemCountStr = oss.str();
327 
328  return makeListNodeClassNamePrefix + itemCountStr + "." + itemTypeName;
329 }
330 
335 {
336  return itemCount;
337 }
338 
343 {
344  return listType;
345 }
346 
351 {
352  if (portClass->getPortType() != VuoPortClass::dataAndEventPort)
353  return NULL;
354 
355  string typeName = VuoGenericType::createGenericTypeName(1);
356  return new VuoGenericType(typeName, vector<string>());
357 }
358 
363 {
364  return "vuo.list.make";
365 }
366 
371 {
372  return makeListNodeClassDescription;
373 }
374 
379 {
381  return NULL;
382 }
383 
387 string VuoCompilerMakeListNodeClass::createUnspecializedNodeClassName(set<VuoPortClass *> portClassesToUnspecialize)
388 {
389  bool foundDataAndEvent = false;
390  for (set<VuoPortClass *>::iterator i = portClassesToUnspecialize.begin(); i != portClassesToUnspecialize.end(); ++i)
391  if ((*i)->getPortType() == VuoPortClass::dataAndEventPort)
392  foundDataAndEvent = true;
393 
394  if (! foundDataAndEvent)
395  return getBase()->getClassName();
396 
398 }
399 
404 string VuoCompilerMakeListNodeClass::createSpecializedNodeClassNameWithReplacement(string genericTypeName, string specializedTypeName)
405 {
406  unsigned long itemCount = 0;
407  string itemTypeName;
408  parseNodeClassName(getBase()->getClassName(), itemCount, itemTypeName);
409 
410  string specializedItemTypeName = (itemTypeName == genericTypeName ? specializedTypeName : itemTypeName);
411  return buildNodeClassName(itemCount, specializedItemTypeName);
412 }