1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13
14
15 #include "lex.h"
16 #include "Ark.h"
17 #include "Parameter.h"
18 #include "ParameterDefinition.h"
19 #include "List.h"
20 #include "ListIterator.h"
21
22 //////////////////////////////////////////////////////////////////////////////
Parameter(ParameterDefinition * pd)23 Parameter::Parameter(ParameterDefinition *pd)
24 {
25 this->definition = pd;
26 this->value = NUL(DXValue*);
27 this->dirty = TRUE;
28 this->defaultingWhenUnconnected = TRUE;
29 if (pd) {
30 this->visible = pd->getDefaultVisibility();
31 this->cacheability = pd->getDefaultCacheability();
32 } else {
33 this->visible = TRUE;
34 this->cacheability = OutputFullyCached;
35 }
36 }
37
38 //
39 // Delete all non-static state associated with a Parameter.
40 // Don't delete the definition as that is a pointer into the Parameter
41 // definition list of a NodeDefinition.
42 // Don't delete the arcs from the arc list, as the Network should do
43 // that. We can however, clear the list (remove the links).
44 //
~Parameter()45 Parameter::~Parameter()
46 {
47 if (this->value)
48 delete this->value;
49
50 this->disconnectArks();
51
52 }
53 //
54 // Remove all the Arks connected to this parameter.
55 //
disconnectArks()56 void Parameter::disconnectArks()
57 {
58 //
59 // call getElement(1) because the arc destructor will
60 // remove itself from the parameter list. So, the
61 // arc that should be destroyed is always the first
62 // element in the list.
63 //
64 Ark *a;
65 while ( (a = (Ark*) this->arcs.getElement(1)) )
66 delete a;
67
68 }
69 //
70 // Return true if the Executive needs to know the value of this parameter
71 //
isNeededValue(boolean ignoreDirty)72 boolean Parameter::isNeededValue(boolean ignoreDirty)
73 {
74 if (this->definition->isInput()) { // An input
75 if (!this->isConnected())
76 return ignoreDirty || this->isDirty();
77 } else if (this->isConnected()) { // An output
78 return ignoreDirty || this->isDirty();
79 }
80
81 return FALSE;
82 }
83
84 //
85 // For the given type, try and augment the given string value with
86 // syntactic sugar to coerce the given value to the given type.
87 // The types we can coerce are StringType, ListType, VectorType and TensorType.
88 // Return T/F indicating whether the value was successfully set (and coerced)
89 //
coerceAndSetValue(const char * value,Type type)90 boolean Parameter::coerceAndSetValue(const char *value, Type type)
91 {
92 char *s = DXValue::CoerceValue(value, type);
93 boolean r = FALSE;
94 if (s) {
95 r = this->value->setValue(s, type);
96 delete s;
97 }
98 return r;
99 }
100 //
101 // Set this parameter to have the given value which must match one of the
102 // types in the ParameterDefinition's list of types.
103 // On success return the Type the value was found to match, and set the value
104 // of this parameter to the value given.
105 // On failure, return DXType::UndefinedType
106 //
setValue(const char * value)107 Type Parameter::setValue(const char *value)
108 {
109 DXType *dxtype;
110 Type type;
111 ParameterDefinition *pd;
112 ListIterator iterator;
113
114 if (!value) {
115 if (this->setValue(NULL, DXType::UndefinedType))
116 return DXType::UndefinedType;
117 else if (this->hasValue())
118 return this->getValueType();
119 else
120 return DXType::UndefinedType;
121 }
122
123 pd = this->getDefinition();
124
125 ASSERT(pd);
126
127 //
128 // Try matching the value to the type without coersion first.
129 //
130 FOR_EACH_PARAM_TYPE(pd, dxtype, iterator) {
131 type = dxtype->getType();
132 if (this->setValue(value,type, FALSE))
133 return type;
134 }
135
136 //
137 // If the above didn't work, lets try and coerce the values
138 //
139 FOR_EACH_PARAM_TYPE(pd, dxtype, iterator) {
140 type = dxtype->getType();
141 if (this->setValue(value,type, TRUE))
142 return type;
143 }
144
145 return DXType::UndefinedType;
146 }
setValue(const char * value,Type type,boolean coerce)147 boolean Parameter::setValue(const char *value, Type type, boolean coerce)
148 {
149 boolean success;
150
151 if (!this->value)
152 this->value = new DXValue;
153
154
155 if (type == DXType::UndefinedType AND NOT value) {
156 if (this->value) delete this->value;
157 this->value = NUL(DXValue*);
158 success = TRUE;
159 } else {
160 ParameterDefinition *pd = this->getDefinition();
161 ListIterator li(*pd->getTypes());
162 DXType *dxt;
163 boolean typeMatch = FALSE;
164 while( (dxt = (DXType*)li.getNext()) )
165 if (dxt->MatchType(type, dxt->getType()))
166 {
167 typeMatch = TRUE;
168 break;
169 }
170
171 if (typeMatch && (
172 this->value->setValue(value, type) ||
173 (coerce && this->coerceAndSetValue(value,type)))) {
174 success = TRUE;
175 } else
176 success = FALSE;
177 }
178
179 if (success) {
180 this->setDirty();
181 if (type == DXType::UndefinedType AND NOT value)
182 this->setUnconnectedDefaultingStatus(TRUE);
183 else
184 this->setUnconnectedDefaultingStatus(FALSE);
185 }
186
187 return success;
188 }
189 //
190 // Set the stored value.
191 // If the parameter is not defaulting, this is
192 // the same as setValue, but if it is defaulting, then we set the
193 // value but leave the parameter clean and defaulting.
194 //
setSetValue(const char * value,Type type)195 boolean Parameter::setSetValue(const char *value, Type type)
196 {
197 boolean was_defaulting = this->defaultingWhenUnconnected;
198
199 boolean r = this->setValue(value,type);
200
201 if (was_defaulting) {
202 this->clearDirty();
203 this->setUnconnectedDefaultingStatus();
204 }
205 return r;
206 }
207
208 //
209 // This method is somewhat of a hack, but at least it belongs here and
210 // not in ScalarNode.C which is what uses it (for now anyway).
211 //
212 // Get the number of component of a vector, scalar or integer. For scalars
213 // and integers, the component count is 1.
214 //
getComponentCount()215 int Parameter::getComponentCount()
216 {
217 int ret = 0;
218
219 switch (this->getValueType()) {
220 case DXType::IntegerListType:
221 case DXType::ScalarListType:
222 case DXType::IntegerType:
223 case DXType::ScalarType:
224 case DXType::FlagType:
225 ret = 1;
226 break;
227 case DXType::VectorType:
228 case DXType::VectorListType:
229 ret = this->value->getVectorComponentCount();
230 break;
231 default:
232 ASSERT(0);
233 }
234 return ret;
235 }
236 //
237 // This method is somewhat of a hack, but at least it belongs here and
238 // not in ScalarNode.C which is what uses it (for now anyway).
239 //
240 // Get the n'th component of a vector, scalar or integer. For scalars
241 // and integers, the component number must be 1.
242 // Components are indexed from 1.
243 //
getComponentValue(int component)244 double Parameter::getComponentValue(int component)
245 {
246 double ret = 0;
247 ASSERT(component > 0);
248
249 switch (this->getValueType()) {
250 case DXType::FlagType:
251 case DXType::IntegerType:
252 ASSERT(component == 1);
253 ret = (double)this->getIntegerValue();
254 break;
255 case DXType::ScalarType:
256 ASSERT(component == 1);
257 ret = this->getScalarValue();
258 break;
259 case DXType::VectorType:
260 ret = this->getVectorComponentValue(component);
261 break;
262 default:
263 ASSERT(0);
264 }
265 return ret;
266 }
267
268 //
269 // This method is somewhat of a hack, but at least it belongs here and
270 // not in ScalarNode.C which is what uses it (for now anyway).
271 //
272 // Set the n'th component of a vector, scalar or integer. For scalars
273 // and integers, the component number must be 1.
274 // Components are indexed from 1.
275 //
setComponentValue(int component,double val)276 boolean Parameter::setComponentValue(int component, double val)
277 {
278 ASSERT(component > 0);
279 DXValue *v = this->value;
280 boolean r = true;
281
282 ASSERT(v);
283
284 switch (this->getValueType()) {
285 case DXType::FlagType:
286 ASSERT(component == 1);
287 r = v->setInteger(val == 0.0 ? 0 : 1);
288 break;
289 case DXType::IntegerType:
290 ASSERT(component == 1);
291 r = v->setInteger((int)val);
292 break;
293 case DXType::ScalarType:
294 ASSERT(component == 1);
295 r = v->setScalar(val);
296 break;
297 case DXType::VectorType:
298 r = v->setVectorComponentValue(component, val);
299 break;
300 default:
301 ASSERT(0);
302 }
303 this->setDirty();
304 return r;
305 }
306 //
307 // Determine if this instance is derived from the given class
308 //
isA(const char * classname)309 boolean Parameter::isA(const char *classname)
310 {
311 Symbol s = theSymbolManager->registerSymbol(classname);
312 return this->isA(s);
313 }
314 //
315 // Determine if this instance is derived from the given class
316 //
isA(Symbol classname)317 boolean Parameter::isA(Symbol classname)
318 {
319 Symbol s = theSymbolManager->registerSymbol(ClassParameter);
320 return (s == classname);
321 }
322
isDefaulting()323 boolean Parameter::isDefaulting()
324 {
325 if (this->isInput() && this->isConnected())
326 return FALSE;
327 else
328 return this->defaultingWhenUnconnected;
329 }
setUnconnectedDefaultingStatus(boolean defaulting)330 void Parameter::setUnconnectedDefaultingStatus(boolean defaulting)
331 {
332 if (this->defaultingWhenUnconnected != defaulting)
333 {
334 this->setDirty();
335 this->defaultingWhenUnconnected = defaulting;
336 }
337 }
addArk(Ark * a)338 boolean Parameter::addArk(Ark *a)
339 {
340 boolean r = this->arcs.appendElement((const void*)a);
341
342 //
343 // If this is the first arc and this is an output parameter,
344 // be sure it gets sent on the next execution (assuming someone
345 // asks this parameter if it needs to be sent).
346 //
347 if (r && (this->arcs.getSize() == 1) && !this->isInput())
348 this->setDirty();
349
350 return r;
351 }
352
353 //
354 // Get the selectable values for this parameter.
355 // This returns a pointer to a constant array of pointers to
356 // constant strings which is NOT to be manipulated by the caller.
357 // NULL may be returned;
358 // The returned array of pointers is NULL terminated.
359 //
getValueOptions()360 const char* const *Parameter::getValueOptions()
361 {
362 return this->definition->getValueOptions();
363 }
364
365 #ifdef DXUI_DEVKIT
366 //
367 // Get any variable declarations that will be required by the code
368 // generated in getObjectCreateCode(). NULL is returned if none required.
369 // The returned string must be freed by the caller.
370 //
getObjectCodeDecl(const char * indent,const char * tag)371 char *Parameter::getObjectCodeDecl(const char *indent, const char *tag)
372 {
373 if (!this->hasValue())
374 return NULL;
375
376 char *p, *code = new char[1024];
377 Type type = this->getValueType();
378 int i, count,items,tuples, hasDecimal;
379 double *values, *data;
380
381 switch (this->getValueType()) {
382
383 case DXType::IntegerListType:
384 case DXType::VectorListType:
385 case DXType::ScalarListType:
386
387 items = DXValue::GetDoublesFromList(
388 this->getValueString(),type,&data,&tuples);
389
390 count = items * tuples;
391
392 for (i = hasDecimal = 0; i < count && ! hasDecimal; i++)
393 if ((int)data[i] != data[i])
394 hasDecimal = 1;
395
396 if (hasDecimal)
397 {
398 sprintf(code,"%sfloat %s_tmp1[] = { ",indent, tag);
399 for (i=0, p = code+STRLEN(code) ; i<count ; i++, p+=STRLEN(p))
400 {
401 sprintf(p," %g", data[i]);
402 if (i != (count-1) && count > 1) strcat(p,", ");
403 }
404 strcat(p,"};\n");
405 }
406 else
407 {
408 sprintf(code,"%sint %s_tmp1[] = { ",indent, tag);
409 for (i=0, p = code+STRLEN(code) ; i<count ; i++, p+=STRLEN(p))
410 {
411 sprintf(p," %d", (int)data[i]);
412 if (i != (count-1) && count > 1) strcat(p,", ");
413 }
414 strcat(p,"};\n");
415 }
416
417 delete data;
418
419 break;
420
421 case DXType::FlagType:
422 case DXType::IntegerType:
423 case DXType::ScalarType:
424 case DXType::VectorType:
425 count = this->getComponentCount();
426
427 values = new double[count];
428
429 for (i = hasDecimal = 0; i < count; i++)
430 {
431 values[i] = this->getComponentValue(i+1);
432 if ((int)values[i] != values[i])
433 hasDecimal = 1;
434 }
435
436 if (hasDecimal)
437 {
438 sprintf(code,"%sfloat %s_tmp1[] = { ",indent, tag);
439 for (i=0, p = code+STRLEN(code) ; i<count ; i++, p+=STRLEN(p))
440 {
441 sprintf(p," %g", values[i]);
442 if (i != (count-1) && count > 1) strcat(p,", ");
443 }
444 strcat(p,"};\n");
445 }
446 else
447 {
448 sprintf(code,"%sint %s_tmp1[] = { ",indent, tag);
449 for (i=0, p = code+STRLEN(code) ; i<count ; i++, p+=STRLEN(p))
450 {
451 sprintf(p," %g", values[i]);
452 if (i != (count-1) && count > 1) strcat(p,", ");
453 }
454 strcat(p,"};\n");
455 }
456
457 delete values;
458
459 break;
460
461 default:
462 delete code;
463 code = NULL;
464
465 }
466
467 return code;
468
469 }
470 //
471 // Get a string that represents the libDX C code to generate
472 // a DX Object from the value of the parameter. The code is
473 // created to assign the object to the given lvalue variable name.
474 // The returned string must be freed by the caller.
475 //
getObjectCreateCode(const char * indent,const char * tag,const char * lvalue)476 char *Parameter::getObjectCreateCode(const char *indent,
477 const char *tag, const char *lvalue)
478 {
479 if (!this->hasValue())
480 return NULL;
481
482 char *listitem, *code = new char[1024], varspec[128];
483 int i, rank, shape, items;
484 Type type = this->getValueType();
485 DXTensor tensor;
486 boolean r;
487 int count, hasDecimal;
488 double *data;
489
490 switch (this->getValueType()) {
491
492 case DXType::IntegerListType:
493 case DXType::VectorListType:
494 case DXType::ScalarListType:
495
496 items = DXValue::GetDoublesFromList(
497 this->getValueString(),type,&data,&shape);
498
499 count = items * shape;
500
501 for (i = hasDecimal = 0; i < count && ! hasDecimal; i++)
502 if ((int)data[i] != data[i])
503 hasDecimal = 1;
504
505
506 delete data;
507 break;
508
509 case DXType::FlagType:
510 case DXType::IntegerType:
511 case DXType::ScalarType:
512 case DXType::VectorType:
513
514 items = 1;
515 shape = count = this->getComponentCount();
516
517 for (i = hasDecimal = 0; i < count; i++)
518 {
519 double value = this->getComponentValue(i+1);
520 if ((int)value != value)
521 hasDecimal = 1;
522 }
523
524 break;
525
526 case DXType::StringType:
527 sprintf(code,
528 "%s%s = (Object)DXNewString(%s);\n",
529 indent,lvalue,this->getValueString());
530 return code;
531
532 default:
533 sprintf(code,"%s%s = NULL;\n",indent,lvalue);
534 fprintf(stderr,"Conversion to DX Object for type %s"
535 " not supported yet.\n",DXType::TypeToString(type));
536 return code;
537 }
538
539 rank = (shape == 1) ? 0 : 1;
540
541 sprintf(code,
542 " %s = (Object)DXNewArray(%s, CATEGORY_REAL, %d, %d);\n"
543 " if (%s == NULL) goto error;\n"
544 " if (DXAddArrayData((Array)%s,0,%d,%s_tmp1) == NULL)\n"
545 " goto error;\n",
546 lvalue, hasDecimal ? "TYPE_FLOAT" : "TYPE_INT", rank, shape,
547 lvalue,
548 lvalue, items, tag);
549
550 return code;
551 }
552 //
553 // Generate code to clean up after the code from getObjectCreateCode()
554 // was executed. lvalue must be the same value that was passed to
555 // getObjectCreateCode().
556 // NULL may be returned;
557 // The returned string must be freed by the caller.
558 //
getObjectCleanupCode(const char * indent,const char * tag)559 char *Parameter::getObjectCleanupCode(const char *indent, const char *tag)
560 {
561
562 if (!this->hasValue())
563 return NULL;
564
565 char *code = new char[1024];
566 Type type = this->getValueType();
567 switch (this->getValueType()) {
568
569 default:
570 delete code;
571 code = NULL;
572 }
573
574 return code;
575 return NULL;
576 }
577 #endif // DXUI_DEVKIT
578