Goby v2
message_val.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Goby Underwater Autonomy Project Libraries
8 // ("The Goby Libraries").
9 //
10 // The Goby Libraries are free software: you can redistribute them and/or modify
11 // them under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // The Goby Libraries are distributed in the hope that they will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
22 
23 #include <iomanip>
24 #include <stdexcept>
25 
26 #include <boost/foreach.hpp>
27 
28 #include <boost/lexical_cast.hpp>
29 #include <boost/numeric/conversion/cast.hpp>
30 
31 #include "goby/util/as.h"
32 #include "goby/util/sci.h"
33 
34 #include "goby/acomms/dccl.h"
35 #include "message_val.h"
36 
37 using goby::util::as;
38 
39 void goby::transitional::DCCLMessageVal::init()
40 {
41  sval_ = "";
42  dval_ = 0;
43  lval_ = 0;
44  bval_ = false;
45  precision_ = MAX_DBL_PRECISION;
46  type_ = cpp_notype;
47 }
48 
50 
52 {
53  init();
54  sval_ = s;
55  type_ = cpp_string;
56 }
57 
59 {
60  init();
61  sval_ = s;
62  type_ = cpp_string;
63 }
64 
65 goby::transitional::DCCLMessageVal::DCCLMessageVal(double d, int p /* = MAX_DBL_PRECISION*/)
66 {
67  init();
68  dval_ = d;
69  precision_ = p;
70  type_ = cpp_double;
71 }
72 
74 {
75  init();
76  dval_ = f;
77  type_ = cpp_double;
78 }
79 
81 {
82  init();
83  lval_ = l;
84  type_ = cpp_long;
85 }
86 
88 {
89  init();
90  lval_ = i;
91  type_ = cpp_long;
92 }
93 
95 {
96  init();
97  bval_ = b;
98  type_ = cpp_bool;
99 }
100 
101 goby::transitional::DCCLMessageVal::DCCLMessageVal(const std::vector<DCCLMessageVal>& vm)
102 {
103  if (vm.size() != 1)
104  throw(goby::acomms::DCCLException(
105  "vector cast to DCCLMessageVal failed: vector is not size 1"));
106  else
107  *this = vm[0];
108 }
109 
111 {
112  sval_ = sval;
113  type_ = cpp_string;
114 }
115 void goby::transitional::DCCLMessageVal::set(double dval, int precision /* = MAX_DBL_PRECISION */)
116 {
117  dval_ = dval;
118  type_ = cpp_double;
119  precision_ = precision;
120 }
122 {
123  lval_ = lval;
124  type_ = cpp_long;
125 }
127 {
128  bval_ = bval;
129  type_ = cpp_bool;
130 }
131 
132 bool goby::transitional::DCCLMessageVal::get(std::string& s) const
133 {
134  std::stringstream ss;
135  switch (type_)
136  {
137  case cpp_string: s = sval_; return true;
138 
139  case cpp_double:
140  if ((log10(abs(dval_)) + precision_) <= MAX_DBL_PRECISION)
141  ss << std::fixed << std::setprecision(precision_) << dval_;
142  else
143  ss << std::setprecision(precision_) << dval_;
144 
145  s = ss.str();
146  return true;
147 
148  case cpp_long: s = as<std::string>(lval_); return true;
149 
150  case cpp_bool: s = (bval_) ? "true" : "false"; return true;
151 
152  default: return false;
153  }
154 }
155 
157 {
158  switch (type_)
159  {
160  case cpp_string:
161  if (boost::iequals(sval_, "true") || boost::iequals(sval_, "1"))
162  b = true;
163  else if (boost::iequals(sval_, "false") || boost::iequals(sval_, "0"))
164  b = false;
165  else
166  return false;
167  return true;
168 
169  case cpp_double:
170  try
171  {
172  b = boost::numeric_cast<bool>(dval_);
173  }
174  catch (...)
175  {
176  return false;
177  }
178  return true;
179 
180  case cpp_long:
181  try
182  {
183  b = boost::numeric_cast<bool>(lval_);
184  }
185  catch (...)
186  {
187  return false;
188  }
189  return true;
190 
191  case cpp_bool: b = bval_; return true;
192 
193  default: return false;
194  }
195 }
196 
198 {
199  switch (type_)
200  {
201  case cpp_string:
202  try
203  {
204  double d = boost::lexical_cast<double>(sval_);
205  t = boost::numeric_cast<long>(util::unbiased_round(d, 0));
206  }
207  catch (...)
208  {
209  if (boost::iequals(sval_, "true"))
210  t = 1;
211  else if (boost::iequals(sval_, "false"))
212  t = 0;
213  else
214  return false;
215  }
216  return true;
217 
218  case cpp_double:
219  try
220  {
221  t = boost::numeric_cast<long>(util::unbiased_round(dval_, 0));
222  }
223  catch (...)
224  {
225  return false;
226  }
227  return true;
228 
229  case cpp_long: t = lval_; return true;
230 
231  case cpp_bool: t = (bval_) ? 1 : 0; return true;
232 
233  default: return false;
234  }
235 }
236 
238 {
239  switch (type_)
240  {
241  case cpp_string:
242  try
243  {
244  d = boost::lexical_cast<double>(sval_);
245  }
246  catch (boost::bad_lexical_cast&)
247  {
248  if (boost::iequals(sval_, "true"))
249  d = 1;
250  else if (boost::iequals(sval_, "false"))
251  d = 0;
252  else
253  return false;
254  }
255  return true;
256 
257  case cpp_double: d = dval_; return true;
258 
259  case cpp_long:
260  try
261  {
262  d = boost::numeric_cast<double>(lval_);
263  }
264  catch (...)
265  {
266  return false;
267  }
268  return true;
269 
270  case cpp_bool: d = (bval_) ? 1 : 0; return true;
271 
272  default: return false;
273  }
274 }
275 
276 goby::transitional::DCCLMessageVal::operator double() const
277 {
278  double d;
279  if (get(d))
280  return d;
281  else
282  return std::numeric_limits<double>::quiet_NaN();
283 }
284 
285 goby::transitional::DCCLMessageVal::operator bool() const
286 {
287  bool b;
288  if (get(b))
289  return b;
290  else
291  return false;
292 }
293 
294 goby::transitional::DCCLMessageVal::operator std::string() const
295 {
296  std::string s;
297  if (get(s))
298  return s;
299  else
300  return "";
301 }
302 
303 goby::transitional::DCCLMessageVal::operator long() const
304 {
305  long l;
306  if (get(l))
307  return l;
308  else
309  return 0;
310 }
311 
312 goby::transitional::DCCLMessageVal::operator int() const { return long(*this); }
313 
314 goby::transitional::DCCLMessageVal::operator unsigned() const { return long(*this); }
315 
316 goby::transitional::DCCLMessageVal::operator float() const { return double(*this); }
317 
318 goby::transitional::DCCLMessageVal::operator std::vector<goby::transitional::DCCLMessageVal>() const
319 {
320  return std::vector<DCCLMessageVal>(1, *this);
321 }
322 
323 bool goby::transitional::DCCLMessageVal::operator==(const DCCLMessageVal& mv) const
324 {
325  switch (mv.type_)
326  {
327  case cpp_string: return mv == sval_;
328  case cpp_double: return mv == dval_;
329  case cpp_long: return mv == lval_;
330  case cpp_bool: return mv == bval_;
331  default: return false;
332  }
333 }
334 
335 bool goby::transitional::DCCLMessageVal::operator==(const std::string& s) const
336 {
337  std::string us;
338  return get(us) && us == s;
339 }
340 
341 bool goby::transitional::DCCLMessageVal::operator==(double d) const
342 {
343  double us;
344  return get(us) && us == d;
345 }
346 
347 bool goby::transitional::DCCLMessageVal::operator==(long l) const
348 {
349  long us;
350  return get(us) && us == l;
351 }
352 
353 bool goby::transitional::DCCLMessageVal::operator==(bool b) const
354 {
355  bool us;
356  return get(us) && us == b;
357 }
358 
359 std::ostream& goby::transitional::operator<<(std::ostream& os,
361 {
362  switch (mv.type_)
363  {
364  case cpp_string: return os << "std::string: " << mv.sval_;
365  case cpp_double:
366  return os << "double: " << std::fixed << std::setprecision(mv.precision_) << mv.dval_;
367  case cpp_long: return os << "long: " << mv.lval_;
368  case cpp_bool: return os << "bool: " << std::boolalpha << mv.bval_;
369  default: return os << "{empty}";
370  }
371 }
372 
373 std::ostream& goby::transitional::
374 operator<<(std::ostream& os, const std::vector<goby::transitional::DCCLMessageVal>& vm)
375 {
376  int j = 0;
377  BOOST_FOREACH (const DCCLMessageVal& m, vm)
378  {
379  if (j)
380  os << ",";
381  os << m;
382  ++j;
383  }
384  return os;
385 }
void set(std::string sval)
set the value with a string (overwrites previous value regardless of type)
bool get(std::string &s) const
extract as std::string (all reasonable casts are done)
std::ostream & operator<<(std::ostream &out, const std::map< std::string, Value > &m)
use this for displaying a human readable version