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