SMTK  @SMTK_VERSION@
Simulation Modeling Tool Kit
ValueItemTemplate.h
1 //=========================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //=========================================================================
10 // .NAME ValueItemTemplate.h -
11 // .SECTION Description
12 // .SECTION See Also
13 
14 #ifndef smtk_attribute_ValueItemTemplate_h
15 #define smtk_attribute_ValueItemTemplate_h
16 
17 #include "smtk/attribute/ComponentItem.h"
18 #include "smtk/attribute/Evaluator.h"
19 #include "smtk/attribute/ValueItem.h"
20 #include "smtk/attribute/ValueItemDefinitionTemplate.h"
21 #include "smtk/io/Logger.h"
22 #include <cassert>
23 #include <cstdio>
24 #include <limits>
25 #include <sstream>
26 #include <vector>
27 
28 namespace smtk
29 {
30 namespace attribute
31 {
32 template<typename DataT>
34 {
35  //template<DataT> friend class ValueItemDefinitionTemplate;
36 public:
37  typedef DataT DataType;
38  typedef typename std::vector<DataT> value_type;
39  typedef value_type const_iterator;
41 
42  ~ValueItemTemplate() override = default;
43  typename std::vector<DataT>::const_iterator begin() const { return m_values.begin(); }
44  typename std::vector<DataT>::const_iterator end() const { return m_values.end(); }
45  bool setNumberOfValues(std::size_t newSize) override;
46 
47  DataT value(std::size_t element = 0) const;
48  DataT value(smtk::io::Logger& log) const { return this->value(0, log); }
49  DataT value(std::size_t element, smtk::io::Logger& log) const;
50 
51  std::string valueAsString() const override { return this->valueAsString(0); }
52  std::string valueAsString(std::size_t element) const override;
53  bool setValue(const DataT& val) { return this->setValue(0, val); }
54  bool setValue(std::size_t element, const DataT& val);
55  bool setValueFromString(std::size_t element, const std::string& val) override;
56  template<typename I>
57  bool setValues(I vbegin, I vend)
58  {
59  bool ok = false;
60  std::size_t num = vend - vbegin;
61  if (this->setNumberOfValues(num))
62  {
63  ok = true;
64  std::size_t i = 0;
65  for (I it = vbegin; it != vend; ++it, ++i)
66  {
67  if (!this->setValue(i, *it))
68  {
69  ok = false;
70  break;
71  }
72  }
73  }
74  return ok;
75  }
76  bool appendValue(const DataT& val);
77  bool removeValue(std::size_t element);
78  void reset() override;
79  bool rotate(std::size_t fromPosition, std::size_t toPosition) override;
80  bool setToDefault(std::size_t element = 0) override;
81  bool isUsingDefault(std::size_t element) const override;
82  bool isUsingDefault() const override;
83  DataT defaultValue() const;
84  const std::vector<DataT>& defaultValues() const;
85 
86  using Item::assign;
87  // Assigns this item to be equivalent to another. Options are processed by derived item classes
88  // Returns true if success and false if a problem occurred. By default, an attribute being used by this
89  // to represent an expression will be copied if needed. Use itemOptions.setIgnoreExpressions option to prevent this
90  // When an expression attribute is copied, its associations are by default not.
91  // Use attributeOptions.setCopyAssociations option if you want them copied as well.These options are defined in CopyAssigmentOptions.h .
92  bool assign(
93  const smtk::attribute::ConstItemPtr& sourceItem,
94  const CopyAssignmentOptions& options,
95  smtk::io::Logger& logger) override;
96 
97  shared_ptr<const DefType> concreteDefinition() const
98  {
99  return dynamic_pointer_cast<const DefType>(this->definition());
100  }
101 
102 protected:
103  ValueItemTemplate(Attribute* owningAttribute, int itemPosition);
104  ValueItemTemplate(Item* owningItem, int myPosition, int mySubGroupPosition);
105  bool setDefinition(smtk::attribute::ConstItemDefinitionPtr vdef) override;
106  void updateDiscreteValue(std::size_t element) override;
107  std::vector<DataT> m_values;
108  const std::vector<DataT> m_dummy; //(1, DataT());
109 
110 private:
111  std::string streamValue(const DataT& val) const;
112 };
113 
114 template<typename DataT>
115 ValueItemTemplate<DataT>::ValueItemTemplate(Attribute* owningAttribute, int itemPosition)
116  : ValueItem(owningAttribute, itemPosition)
117  , m_dummy(1, DataT())
118 {
119 }
120 
121 template<typename DataT>
122 ValueItemTemplate<DataT>::ValueItemTemplate(
123  Item* inOwningItem,
124  int itemPosition,
125  int mySubGroupPosition)
126  : ValueItem(inOwningItem, itemPosition, mySubGroupPosition)
127  , m_dummy(1, DataT())
128 {
129 }
130 
131 template<typename DataT>
132 DataT ValueItemTemplate<DataT>::value(std::size_t element) const
133 {
134  return this->value(element, smtk::io::Logger::instance());
135 }
136 
137 // When DataT does not have a default constructor, as in the case of double or
138 // int. DataT() results in a zero-initialized value:
139 // https://en.cppreference.com/w/cpp/language/value_initialization
140 template<typename DataT>
141 DataT ValueItemTemplate<DataT>::value(std::size_t element, smtk::io::Logger& log) const
142 {
143  if (!this->isSet(element))
144  {
146  log,
147  "Item \"" << this->name() << "\" element " << element << " is not set (attribute \""
148  << this->attribute()->name() << "\").");
149  return DataT();
150  }
151 
152  if (isExpression())
153  {
154  smtk::attribute::AttributePtr expAtt = expression();
155  if (!expAtt)
156  {
158  log,
159  "Item \"" << this->name() << "\" has no referemce expression (attribute \""
160  << this->attribute()->name() << "\").");
161  return DataT();
162  }
163 
164  std::unique_ptr<smtk::attribute::Evaluator> evaluator = expAtt->createEvaluator();
165  if (!evaluator)
166  {
168  log,
169  "Item \"" << this->name() << "\" expression is not evaluatable (attribute \""
170  << this->attribute()->name() << "\").");
171  return DataT();
172  }
173 
174  smtk::attribute::Evaluator::ValueType result;
175  // |evaluator| will report errors in |log| for the caller.
176  if (!evaluator->evaluate(
177  result, log, element, Evaluator::DependentEvaluationMode::EVALUATE_DEPENDENTS))
178  {
179  return DataT();
180  }
181 
182  DataT resultAsDataT;
183  try
184  {
185  resultAsDataT = boost::get<DataT>(result);
186  }
187  catch (const boost::bad_get&)
188  {
190  log,
191  "Item \"" << this->name() << "\" evaluation result was not compatible (attribute \""
192  << this->attribute()->name() << "\").");
193  return DataT();
194  }
195 
196  return resultAsDataT;
197  }
198  else
199  {
200  return m_values[element];
201  }
202 }
203 
204 template<typename DataT>
205 bool ValueItemTemplate<DataT>::setDefinition(smtk::attribute::ConstItemDefinitionPtr tdef)
206 {
207  // Note that we do a dynamic cast here since we don't
208  // know if the proper definition is being passed
209  const DefType* def = dynamic_cast<const DefType*>(tdef.get());
210  // Call the parent's set definition - similar to constructor calls
211  // we call from base to derived
212  if ((def == nullptr) || (!ValueItem::setDefinition(tdef)))
213  {
214  return false;
215  }
216  size_t n = def->numberOfRequiredValues();
217  if (n)
218  {
219  if (def->hasDefault())
220  {
221  // Assumes that if the definition is discrete then default value
222  // will be based on the default discrete index
223  if (def->defaultValues().size() > 1)
224  {
225  m_values = def->defaultValues();
226  }
227  else
228  {
229  m_values.resize(n, def->defaultValue());
230  }
231  }
232  else
233  {
234  m_values.resize(n);
235  }
236  }
237  return true;
238 }
239 
240 template<typename DataT>
241 bool ValueItemTemplate<DataT>::setValueFromString(std::size_t element, const std::string& sval)
242 {
243  // If the string is empty then unset the value.
244  if (sval.empty())
245  {
246  this->unset(element);
247  return true;
248  }
249 
250  std::istringstream iss(sval);
251  DataT val;
252  iss >> val;
253  return !iss.fail() && this->setValue(element, val);
254 }
255 
256 template<typename DataT>
257 bool ValueItemTemplate<DataT>::setValue(std::size_t element, const DataT& val)
258 {
259  const DefType* def = static_cast<const DefType*>(this->definition().get());
260  if (def->isDiscrete())
261  {
262  int index = def->findDiscreteIndex(val);
263  // Is this the current value?
264  assert(m_discreteIndices.size() > element);
265  if (index == m_discreteIndices[element])
266  {
267  return true;
268  }
269 
270  if (index != -1)
271  {
272  m_discreteIndices[element] = index;
273  assert(m_values.size() > element);
274  m_values[element] = val;
275  if (def->allowsExpressions())
276  {
277  m_expression->unset();
278  }
279  assert(m_isSet.size() > element);
280  m_isSet[element] = true;
281  // Update active children if needed - note that
282  // we currently only support active children based on the
283  // 0th value changing
284  if (element == 0)
285  {
286  this->updateActiveChildrenItems();
287  }
288  return true;
289  }
290  return false;
291  }
292  if (def->isValueValid(val))
293  {
294  assert(m_values.size() > element);
295  m_values[element] = val;
296  assert(m_isSet.size() > element);
297  m_isSet[element] = true;
298  if (def->allowsExpressions())
299  {
300  m_expression->unset();
301  }
302  return true;
303  }
304  return false;
305 }
306 
307 template<typename DataT>
308 void ValueItemTemplate<DataT>::updateDiscreteValue(std::size_t element)
309 {
310  const DefType* def = static_cast<const DefType*>(this->definition().get());
311  m_values[element] = def->discreteValue(static_cast<size_t>(m_discreteIndices[element]));
312 }
313 
314 template<typename DataT>
315 std::string ValueItemTemplate<DataT>::valueAsString(std::size_t element) const
316 {
317  if (this->isExpression())
318  {
319  // Can the expression be evaluated by value()? |log| will have errors when
320  // evaluation is not possible or failed.
321  smtk::io::Logger log;
322  DataT val = value(element, log);
323  if (log.hasErrors())
324  {
325  return "CANNOT_EVALUATE";
326  }
327 
328  return streamValue(val);
329  }
330  else
331  {
332  assert(m_isSet.size() > element);
333  if (m_isSet[element])
334  {
335  assert(m_values.size() > element);
336  return streamValue(m_values[element]);
337  }
338 
339  return "VALUE_IS_NOT_SET";
340  }
341 }
342 
343 template<typename DataT>
344 bool ValueItemTemplate<DataT>::appendValue(const DataT& val)
345 {
346  //First - are we allowed to change the number of values?
347  const DefType* def = static_cast<const DefType*>(this->definition().get());
348  if (!this->isExtensible())
349  {
350  return false; // The number of values is fixed
351  }
352 
353  std::size_t n = this->maxNumberOfValues();
354  if (n && (this->numberOfValues() >= n))
355  {
356  return false; // max number reached
357  }
358 
359  if (def->isDiscrete())
360  {
361  int index = def->findDiscreteIndex(val);
362  if (index != -1)
363  {
364  m_values.push_back(val);
365  m_discreteIndices.push_back(index);
366  m_isSet.push_back(true);
367  return true;
368  }
369  return false;
370  }
371  if (def->isValueValid(val))
372  {
373  if (def->allowsExpressions())
374  {
375  m_expression->unset();
376  }
377  m_values.push_back(val);
378  m_isSet.push_back(true);
379  return true;
380  }
381  return false;
382 }
383 
384 template<typename DataT>
385 bool ValueItemTemplate<DataT>::setNumberOfValues(std::size_t newSize)
386 {
387  // If the current size is the same just return
388  if (this->numberOfValues() == newSize)
389  {
390  return true;
391  }
392 
393  //Next - are we allowed to change the number of values?
394  if (!this->isExtensible())
395  {
396  return false; // The number of values is fixed
397  }
398 
399  // Is this size between the required number and the max?
400  if (newSize < this->numberOfRequiredValues())
401  {
402  return false;
403  }
404 
405  std::size_t n = this->maxNumberOfValues();
406  if (n && (newSize > n))
407  {
408  return false; // greater than max number
409  }
410 
411  const DefType* def = static_cast<const DefType*>(this->definition().get());
412  n = this->numberOfValues();
413  // Are we increasing or decreasing?
414  if (newSize < n)
415  {
416  m_values.resize(newSize);
417  m_isSet.resize(newSize);
418  if (def->isDiscrete())
419  {
420  m_discreteIndices.resize(newSize);
421  }
422  return true;
423  }
424  if (def->hasDefault())
425  {
426  if (def->defaultValues().size() == newSize)
427  {
428  m_values = def->defaultValues();
429  }
430  else
431  {
432  m_values.resize(newSize, def->defaultValue());
433  }
434  m_isSet.resize(newSize, true);
435  }
436  else
437  {
438  m_values.resize(newSize);
439  m_isSet.resize(newSize, false);
440  }
441  if (def->isDiscrete())
442  {
443  m_discreteIndices.resize(newSize, def->defaultDiscreteIndex());
444  }
445  return true;
446 }
447 
448 template<typename DataT>
449 bool ValueItemTemplate<DataT>::removeValue(std::size_t i)
450 {
451  const DefType* def = static_cast<const DefType*>(this->definition().get());
452  // If i < the required number of values this is the same as unset - else if
453  // its extensible remove it completely
454  if (i < def->numberOfRequiredValues())
455  {
456  this->unset(i);
457  return true;
458  }
459  if (i >= this->numberOfValues())
460  {
461  return false; // i can't be greater than the number of values
462  }
463  m_values.erase(m_values.begin() + i);
464  m_isSet.erase(m_isSet.begin() + i);
465  if (def->isDiscrete())
466  {
467  m_discreteIndices.erase(m_discreteIndices.begin() + i);
468  }
469  return true;
470 }
471 
472 template<typename DataT>
473 bool ValueItemTemplate<DataT>::setToDefault(std::size_t element)
474 {
475  const DefType* def = static_cast<const DefType*>(this->definition().get());
476  if (!def->hasDefault())
477  {
478  return false; // Doesn't have a default value
479  }
480 
481  if (def->isDiscrete())
482  {
483  this->setDiscreteIndex(element, def->defaultDiscreteIndex());
484  }
485  else
486  {
487  assert(def->defaultValues().size() > element);
488  this->setValue(
489  element,
490  def->defaultValues().size() > 1 ? def->defaultValues()[element] : def->defaultValue());
491  }
492  return true;
493 }
494 
495 template<typename DataT>
496 bool ValueItemTemplate<DataT>::isUsingDefault() const
497 {
498  const DefType* def = static_cast<const DefType*>(this->definition().get());
499  if (!def->hasDefault())
500  {
501  return false; // Doesn't have a default value
502  }
503 
504  std::size_t i, n = this->numberOfValues();
505  const DataT& dval = def->defaultValue();
506  const std::vector<DataT>& dvals = def->defaultValues();
507  bool vectorDefault = (dvals.size() == n);
508  for (i = 0; i < n; i++)
509  {
510  assert(m_isSet.size() > i);
511  assert(m_values.size() > i);
512  if (!(m_isSet[i] && (vectorDefault ? m_values[i] == dvals[i] : m_values[i] == dval)))
513  {
514  return false;
515  }
516  }
517  return true;
518 }
519 
520 template<typename DataT>
521 bool ValueItemTemplate<DataT>::isUsingDefault(std::size_t element) const
522 {
523  const DefType* def = static_cast<const DefType*>(this->definition().get());
524  assert(m_isSet.size() > element);
525  if (!(def->hasDefault() && m_isSet[element]))
526  {
527  return false; // Doesn't have a default value
528  }
529 
530  const DataT& dval = def->defaultValue();
531  const std::vector<DataT>& dvals = def->defaultValues();
532  bool vectorDefault = (dvals.size() == def->numberOfRequiredValues());
533  assert(m_values.size() > element);
534  return (vectorDefault ? m_values[element] == dvals[element] : m_values[element] == dval);
535 }
536 
537 template<typename DataT>
538 DataT ValueItemTemplate<DataT>::defaultValue() const
539 {
540  const DefType* def = static_cast<const DefType*>(this->definition().get());
541  if (!def)
542  return m_dummy[0];
543 
544  return def->defaultValue();
545 }
546 
547 template<typename DataT>
548 const std::vector<DataT>& ValueItemTemplate<DataT>::defaultValues() const
549 {
550  const DefType* def = static_cast<const DefType*>(this->definition().get());
551  if (!def)
552  return m_dummy;
553 
554  return def->defaultValues();
555 }
556 
557 template<typename DataT>
558 void ValueItemTemplate<DataT>::reset()
559 {
560  const DefType* def = static_cast<const DefType*>(this->definition().get());
561  // If we can have an expression then clear it
562  if (def->allowsExpressions())
563  {
564  m_expression->unset();
565  }
566 
567  // Was the initial size 0?
568  std::size_t i, n = this->numberOfRequiredValues();
569  if (this->numberOfValues() != n)
570  {
571  this->setNumberOfValues(n);
572  }
573  if (!n)
574  {
575  m_values.clear();
576  m_isSet.clear();
577  m_discreteIndices.clear();
578  ValueItem::reset();
579  return;
580  }
581 
582  if (!def->hasDefault()) // Do we have default values
583  {
584  for (i = 0; i < n; i++)
585  {
586  this->unset(i);
587  }
588  ValueItem::reset();
589  return;
590  }
591 
592  if (def->isDiscrete())
593  {
594  int index = def->defaultDiscreteIndex();
595  for (i = 0; i < n; i++)
596  {
597  this->setDiscreteIndex(i, index);
598  }
599  }
600  else
601  {
602  DataT dval = def->defaultValue();
603  const std::vector<DataT>& dvals = def->defaultValues();
604  bool vectorDefault = (dvals.size() == n);
605  for (i = 0; i < n; i++)
606  {
607  this->setValue(i, vectorDefault ? dvals[i] : dval);
608  }
609  }
610  ValueItem::reset();
611 }
612 
613 template<typename DataT>
614 bool ValueItemTemplate<DataT>::rotate(std::size_t fromPosition, std::size_t toPosition)
615 {
616  // Let's first verify that ValueItem was OK with the rotation.
617  if (!ValueItem::rotate(fromPosition, toPosition))
618  {
619  return false;
620  }
621 
622  // No need to check to see if the rotation is valid since ValueItem already checked it
623  this->rotateVector(m_values, fromPosition, toPosition);
624  return true;
625 }
626 
627 template<typename DataT>
629  const smtk::attribute::ConstItemPtr& sourceItem,
630  const CopyAssignmentOptions& options,
631  smtk::io::Logger& logger)
632 {
633  if (!ValueItem::assign(sourceItem, options, logger))
634  {
635  return false;
636  }
637  // Cast input pointer to ValueItemTemplate
638  const ValueItemTemplate<DataT>* sourceValueItemTemplate =
639  dynamic_cast<const ValueItemTemplate<DataT>*>(sourceItem.get());
640 
641  if (!sourceValueItemTemplate)
642  {
643  smtkErrorMacro(logger, "Source Item: " << name() << " is not a ValueItemTemplate");
644  return false; // Source is not the right type of item
645  }
646  // If the item is discrete or an expression there is nothing to be done
647  if (sourceValueItemTemplate->isExpression() || sourceValueItemTemplate->isDiscrete())
648  {
649  return true;
650  }
651 
652  // Update values
653  this->setNumberOfValues(sourceValueItemTemplate->numberOfValues());
654 
655  // Were we able to allocate enough space to fit all of the source's values?
656  std::size_t myNumVals, sourceNumVals, numVals;
657  myNumVals = this->numberOfValues();
658  sourceNumVals = sourceValueItemTemplate->numberOfValues();
659  if (myNumVals < sourceNumVals)
660  {
661  // Ok so the source has more values than we can deal with - was partial copying permitted?
662  if (options.itemOptions.allowPartialValues())
663  {
664  numVals = myNumVals;
666  logger,
667  "ValueItem: " << this->name() << "'s number of values (" << myNumVals
668  << ") is smaller than source Item's number of values (" << sourceNumVals
669  << ") - will partially copy the values");
670  }
671  else
672  {
674  logger,
675  "ValueItem: " << name() << "'s number of values (" << myNumVals
676  << ") can not hold source ValueItem's number of values (" << sourceNumVals
677  << ") and Partial Copying was not permitted");
678  return false;
679  }
680  }
681  else
682  {
683  numVals = sourceNumVals;
684  }
685 
686  for (std::size_t i = 0; i < numVals; ++i)
687  {
688  if (sourceValueItemTemplate->isSet(i))
689  {
690  if (!this->setValue(i, sourceValueItemTemplate->value(i)))
691  {
692  if (options.itemOptions.allowPartialValues())
693  {
695  logger,
696  "Could not assign Value:" << sourceValueItemTemplate->value(i)
697  << " to ValueItem: " << sourceItem->name());
698  this->unset(i);
699  }
700  else
701  {
703  logger,
704  "Could not assign Value:" << sourceValueItemTemplate->value(i)
705  << " to ValueItem: " << sourceItem->name()
706  << " and allowPartialValues options was not specified.");
707  return false;
708  }
709  }
710  }
711  }
712  return true;
713 }
714 
715 template<typename DataT>
716 std::string ValueItemTemplate<DataT>::streamValue(const DataT& val) const
717 {
718  std::stringstream buffer;
719  buffer.precision(std::numeric_limits<DataT>::max_digits10);
720  buffer << val;
721  return buffer.str();
722 }
723 
724 } // namespace attribute
725 } // namespace smtk
726 
727 #endif /* smtk_attribute_ValueItemTemplate_h */
smtk
The main namespace for the Simulation Modeling Tool Kit (SMTK).
Definition: doc.h:33
Logger.h
smtk::attribute::CopyAssignmentOptions
Class used to specify copy and assignment options.
Definition: CopyAssignmentOptions.h:211
smtk::attribute::ValueItemTemplate
Definition: ValueItemTemplate.h:33
smtk::attribute::Item::assign
virtual bool assign(const smtk::attribute::ConstItemPtr &sourceItem, unsigned int options)
Assigns this item to be equivalent to another.
Definition: Item.cxx:292
smtk::attribute::ConstItemDefinitionPtr
smtk::shared_ptr< const smtk::attribute::ItemDefinition > ConstItemDefinitionPtr
Definition: PublicPointerDefs.h:475
smtk::attribute::ValueItem::rotate
bool rotate(std::size_t fromPosition, std::size_t toPosition) override
Rotate the order between specified positions.
Definition: ValueItem.cxx:311
smtk::io::Logger
Log messages for later presentation to a user or a file.
Definition: Logger.h:95
smtkErrorMacro
#define smtkErrorMacro(logger, x)
Write the expression x to logger as an error message.
Definition: Logger.h:38
smtk::attribute::Item
Definition: Item.h:43
smtk::attribute::AttributePtr
smtk::shared_ptr< smtk::attribute::Attribute > AttributePtr
Definition: PublicPointerDefs.h:456
smtk::attribute::ValueItemTemplate::rotate
bool rotate(std::size_t fromPosition, std::size_t toPosition) override
Rotate the order between specified positions.
Definition: ValueItemTemplate.h:614
smtk::attribute::ConstItemPtr
smtk::shared_ptr< const smtk::attribute::Item > ConstItemPtr
Definition: PublicPointerDefs.h:469
smtk::attribute::ValueItem
Definition: ValueItem.h:31
smtk::attribute::Attribute
Represent a (possibly composite) value according to a definition.
Definition: Attribute.h:49
smtk::attribute::ValueItemDefinitionTemplate
Definition: ValueItemDefinitionTemplate.h:26
smtk::attribute::ItemAssignmentOptions::allowPartialValues
bool allowPartialValues() const
Methods to set and retrieve the allowPartialValues Option.
Definition: CopyAssignmentOptions.h:147
smtkInfoMacro
#define smtkInfoMacro(logger, x)
Write the expression x to logger as an informational message.
Definition: Logger.h:77