libvisiontransfer  10.0.0
parametervalue.cpp
1 /*******************************************************************************
2  * Copyright (c) 2022 Nerian Vision GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *******************************************************************************/
14 
15 #include <string>
16 #include <vector>
17 #include <cstring>
18 #include <sstream>
19 #include <set>
20 
21 #include <iostream>
22 
23 #include <visiontransfer/parametervalue.h>
24 #include <visiontransfer/conversionhelpers.h>
25 
26 namespace visiontransfer {
27 namespace param {
28 
29 using namespace internal;
30 
31 std::string ParameterValue::sanitizeString(const std::string& s, unsigned int maxLength /* = 4096 */ ) {
32  std::ostringstream ss;
33  const std::string whitelist("-+_,.:@/ "); // plus all alnums
34  unsigned int len = 0;
35  for (const char c: s) {
36  if (std::isalnum(c) || whitelist.find(c) != std::string::npos) {
37  ss << c;
38  } else {
39  ss << ' ';
40  }
41  if (++len > maxLength) break; // Trim excessively long safestrings
42  }
43  return ss.str();
44 }
45 
46 ParameterValue::ParameterValue()
47 : numVal(0.0), type(TYPE_UNDEFINED) {
48 }
49 
50 ParameterValue& ParameterValue::setType(ParameterType t) {
51  type = t;
52  return *this;
53 };
54 
55 ParameterValue& ParameterValue::setTensorShape(const std::vector<unsigned int>& shape) {
56  unsigned int dims = (unsigned int) shape.size();
57  if (dims==0) {
58  throw std::runtime_error("Cannot create a zero-dimensional tensor");
59  }
60  int elems = 1;
61  for (unsigned int i=0; i<dims; ++i) {
62  elems *= shape[i];
63  }
64  if (elems==0) {
65  throw std::runtime_error("Cannot create a tensor with effective size 0");
66  }
67  tensorNumElements = elems;
68  tensorShape = shape;
69  tensorData.reserve(elems);
70  return *this;
71 }
72 
73 bool ParameterValue::isDefined() const {
74  return (type!=TYPE_UNDEFINED);
75 }
76 bool ParameterValue::isUndefined() const {
77  return (type==TYPE_UNDEFINED);
78 }
79 bool ParameterValue::isTensor() const {
80  return type==TYPE_TENSOR;
81 }
82 bool ParameterValue::isScalar() const {
83  return !isTensor();
84 }
85 bool ParameterValue::isCommand() const {
86  return type==TYPE_COMMAND;
87 }
88 
89 unsigned int ParameterValue::getTensorDimension() const {
90  return (unsigned int) tensorShape.size();
91 }
92 
93 std::vector<unsigned int> ParameterValue::getTensorShape() const {
94  return tensorShape;
95 }
96 
97 std::vector<double> ParameterValue::getTensorData() const {
98  return tensorData;
99 }
100 
101 ParameterValue& ParameterValue::setTensorData(const std::vector<double>& data) {
102  if (data.size() != tensorNumElements) throw std::runtime_error("ParameterValue::setTensorData(): wrong number of elements");
103 
104  setType(ParameterType::TYPE_TENSOR);
105  tensorData = data;
106  // Also cache a pre-rendered string version
107  std::ostringstream os;
108  for (unsigned int i=0; i<getTensorNumElements(); ++i) {
109  if (i) os << " ";
110  os << ConversionHelpers::anyToString(tensorData[i]);
111  }
112  stringVal = os.str();
113  return *this;
114 }
115 
116 unsigned int ParameterValue::getTensorNumElements() const {
117  return tensorNumElements;
118 }
119 
120 unsigned int ParameterValue::getTensorCurrentDataSize() const {
121  return (unsigned int) tensorData.size();
122 }
123 
124 // setters
125 template<> VT_EXPORT
126 ParameterValue& ParameterValue::setValue(int t) {
127  // always cache string
128  switch (this->type) {
129  case TYPE_INT:
130  case TYPE_DOUBLE:
131  case TYPE_STRING:
132  case TYPE_SAFESTRING:
133  case TYPE_COMMAND:
134  numVal = t;
135  stringVal = ConversionHelpers::anyToString(t);
136  break;
137  case TYPE_BOOL:
138  numVal = (t==0) ? 0 : 1;
139  stringVal = (t==0) ? "false" : "true";
140  break;
141  case TYPE_TENSOR:
142  // could in theory accept iff tensor is of exactly one-element size
143  throw std::runtime_error("Cannot assign a raw scalar to a tensor parameter");
144  case TYPE_UNDEFINED:
145  throw std::runtime_error("Cannot assign a value to an undefined parameter");
146  }
147  return *this;
148 }
149 
150 double& ParameterValue::tensorElementAt(unsigned int x) {
151  // Pure 1-dim support
152  //if (tensorShape.size()!=1) throw std::runtime_error("ParameterValue::tensorElementAt(): not a tensor of dimension 1");
153  //if (x>=tensorShape[0]) throw std::runtime_error("ParameterValue::tensorElementAt(): access out of bounds");
154  // Any-dim support (allow self-addressing)
155  if (tensorShape.size()==0) throw std::runtime_error("ParameterValue::tensorElementAt(): not a tensor");
156  if (x>=tensorNumElements) throw std::runtime_error("ParameterValue::tensorElementAt(): access out of bounds");
157  return tensorData[x];
158 }
159 double& ParameterValue::tensorElementAt(unsigned int y, unsigned int x) {
160  if (tensorShape.size()!=2) throw std::runtime_error("ParameterValue::tensorElementAt(): not a tensor of dimension 2");
161  if (y>=tensorShape[0] || x>=tensorShape[1]) throw std::runtime_error("ParameterValue::tensorElementAt(): access out of bounds");
162  return tensorData[y*tensorShape[1] + x];
163 }
164 double& ParameterValue::tensorElementAt(unsigned int z, unsigned int y, unsigned int x) {
165  if (tensorShape.size()!=3) throw std::runtime_error("ParameterValue::tensorElementAt(): not a tensor of dimension 3");
166  if (z>=tensorShape[0] || y>=tensorShape[1] || x>=tensorShape[2]) throw std::runtime_error("ParameterValue::tensorElementAt(): access out of bounds");
167  return tensorData[z*tensorShape[1]*tensorShape[2] + y*tensorShape[2] + x];
168 }
169 
170 // setters
171 template<> VT_EXPORT
172 ParameterValue& ParameterValue::setValue(bool t) {
173  // always cache string
174  switch (this->type) {
175  case TYPE_INT:
176  case TYPE_DOUBLE:
177  numVal = t ? 1 : 0;
178  stringVal = ConversionHelpers::anyToString(numVal);
179  break;
180  case TYPE_STRING:
181  case TYPE_SAFESTRING:
182  case TYPE_COMMAND:
183  case TYPE_BOOL:
184  numVal = (t==false) ? 0 : 1;
185  stringVal = (t==false) ? "false" : "true";
186  break;
187  case TYPE_TENSOR:
188  // could in theory accept iff tensor is of exactly one-element size
189  throw std::runtime_error("Cannot assign a raw scalar to a tensor parameter");
190  case TYPE_UNDEFINED:
191  throw std::runtime_error("Cannot assign a value to an undefined parameter");
192  }
193  return *this;
194 }
195 template<> VT_EXPORT
196 ParameterValue& ParameterValue::setValue(double t) {
197  // always cache string
198  switch (this->type) {
199  case TYPE_DOUBLE:
200  case TYPE_STRING:
201  case TYPE_SAFESTRING:
202  case TYPE_COMMAND:
203  numVal = t;
204  stringVal = ConversionHelpers::anyToString(t);
205  break;
206  case TYPE_INT:
207  numVal = (int) t;
208  stringVal = ConversionHelpers::anyToString((int) t); // lose decimals here
209  break;
210  case TYPE_BOOL:
211  numVal = (t==0) ? 0 : 1;
212  stringVal = (t==0) ? "false" : "true";
213  break;
214  case TYPE_TENSOR:
215  // could in theory accept iff tensor is of exactly one-element size
216  throw std::runtime_error("Cannot assign a raw scalar to a tensor parameter");
217  case TYPE_UNDEFINED:
218  throw std::runtime_error("Cannot assign a value to an undefined parameter");
219  }
220  return *this;
221 }
222 
223 template<> VT_EXPORT
224 ParameterValue& ParameterValue::setValue(const char* t) {
225  // always cache string
226  switch (this->type) {
227  case TYPE_COMMAND:
228  case TYPE_SAFESTRING:
229  // sanitize!
230  stringVal = sanitizeString(t);
231  numVal = atof(stringVal.c_str());
232  break;
233  case TYPE_STRING:
234  stringVal = t;
235  numVal = atof(t);
236  break;
237  case TYPE_DOUBLE:
238  numVal = atof(t);
239  stringVal = ConversionHelpers::anyToString(numVal);
240  break;
241  case TYPE_INT:
242  numVal = atol(t);
243  stringVal = ConversionHelpers::anyToString((int) numVal); // lose decimals
244  break;
245  case TYPE_BOOL:
246  if (!std::strncmp("true", t, 4) || !std::strncmp("True", t, 4)) {
247  numVal = 1;
248  } else {
249  numVal = atol(t)==0 ? 0 : 1;
250  }
251  stringVal = (numVal==0.0) ? "false" : "true";
252  break;
253  case TYPE_TENSOR:
254  // could in theory accept iff tensor is of exactly one-element size
255  throw std::runtime_error("Cannot assign a raw scalar to a tensor parameter");
256  case TYPE_UNDEFINED:
257  throw std::runtime_error("Cannot assign a value to an undefined parameter");
258  }
259  return *this;
260 }
261 
262 template<> VT_EXPORT
263 ParameterValue& ParameterValue::setValue(const std::string& t) {
264  return setValue<const char*>(t.c_str());
265 }
266 template<> VT_EXPORT
267 ParameterValue& ParameterValue::setValue(std::string t) {
268  return setValue<const char*>(t.c_str());
269 }
270 
271 // getters
272 template<> VT_EXPORT
273 int ParameterValue::getValue() const {
274  switch (this->type) {
275  case TYPE_INT: case TYPE_DOUBLE: case TYPE_BOOL:
276  return (int) numVal;
277  case TYPE_STRING:
278  case TYPE_SAFESTRING:
279  case TYPE_COMMAND:
280  return (int) numVal; // also ok, since cached
281  case TYPE_TENSOR:
282  // could also return 0 or a dedicated type exception (or be OK if size ==1 element)
283  throw std::runtime_error("Attempted to get tensor parameter as scalar- undefined value");
284  case TYPE_UNDEFINED:
285  default:
286  return 0; // silent default
287  }
288 }
289 template<> VT_EXPORT
290 double ParameterValue::getValue() const {
291  switch (this->type) {
292  case TYPE_INT: case TYPE_DOUBLE: case TYPE_BOOL:
293  return (double) numVal;
294  case TYPE_STRING:
295  case TYPE_SAFESTRING:
296  case TYPE_COMMAND:
297  return (double) numVal; // also ok, since cached
298  case TYPE_TENSOR:
299  // could also return 0 or a dedicated type exception (or be OK if size ==1 element)
300  throw std::runtime_error("Attempted to get tensor parameter as scalar- undefined value");
301  case TYPE_UNDEFINED:
302  default:
303  return 0.0; // silent default
304  }
305 }
306 template<> VT_EXPORT
307 bool ParameterValue::getValue() const {
308  switch (this->type) {
309  case TYPE_INT: case TYPE_DOUBLE: case TYPE_BOOL:
310  return (bool) numVal;
311  case TYPE_STRING:
312  case TYPE_SAFESTRING:
313  case TYPE_COMMAND:
314  return (bool) numVal; // also ok, since cached
315  case TYPE_TENSOR:
316  // could also return 0 or a dedicated type exception (or be OK if size ==1 element)
317  throw std::runtime_error("Attempted to get tensor parameter as scalar- undefined value");
318  case TYPE_UNDEFINED:
319  default:
320  return false; // silent default
321  }
322 }
323 template<> VT_EXPORT
324 std::string ParameterValue::getValue() const {
325  switch (this->type) {
326  case TYPE_INT: case TYPE_DOUBLE: case TYPE_BOOL:
327  // string is pre-rendered
328  case TYPE_TENSOR:
329  // also pre-rendered (in setTensorData)
330  case TYPE_STRING: case TYPE_SAFESTRING: case TYPE_COMMAND:
331  return stringVal;
332  case TYPE_UNDEFINED:
333  default:
334  return ""; // silent default
335  }
336 }
337 
338 // Mainly for literals placed in test code etc - maybe remove?
339 template<> VT_EXPORT
340 const char* ParameterValue::getValue() const {
341  switch (this->type) {
342  case TYPE_INT: case TYPE_DOUBLE: case TYPE_BOOL:
343  // string is pre-rendered
344  case TYPE_TENSOR:
345  // also pre-rendered (in setTensorData)
346  case TYPE_STRING: case TYPE_SAFESTRING: case TYPE_COMMAND:
347  return stringVal.c_str();
348  case TYPE_UNDEFINED:
349  default:
350  return ""; // silent default
351  }
352 }
353 
354 } // namespace param
355 } // namespace visiontransfer
356 
std::vector< double > getTensorData() const
Return a copy of the internal tensor data.
static std::string anyToString(T val)
Converts any type to a string.
Nerian Vision Technologies