MADARA  3.2.3
KnowledgeRecord.cpp
Go to the documentation of this file.
1 #ifndef _KNOWLEDGE_RECORD_CPP_
2 #define _KNOWLEDGE_RECORD_CPP_
3 
6 
8 #include <sstream>
9 #include <algorithm>
10 #include <stdlib.h>
11 #include <iomanip>
12 #include <iostream>
14 
15 namespace {
16  int madara_double_precision (-1);
17 
18  bool madara_use_scientific (false);
19 }
20 
21 namespace madara { namespace knowledge {
22 
23 int
25 {
26  return madara_double_precision;
27 }
28 
29 void
30 KnowledgeRecord::set_precision (int new_precision)
31 {
33  "KnowledgeRecord::set_precision:" \
34  " setting precision to %d\n", madara_double_precision);
35 
36  madara_double_precision = new_precision;
37 }
38 
39 void
41 {
43  "KnowledgeRecord::set_fixed:" \
44  " setting output format to std::fixed\n");
45 
46  madara_use_scientific = false;
47 }
48 
49 void
51 {
53  "KnowledgeRecord::set_scientific:" \
54  " setting output format to std::scientific\n");
55 
56  madara_use_scientific = true;
57 }
58 
59 int
61  const std::string & filename, uint32_t read_as_type)
62 {
63  void * buffer;
64  size_t size;
65  bool add_zero_char = false;
66 
67  // clear the old value
68  clear_value ();
69 
70  std::string::size_type position = filename.rfind ('.');
71  std::string extension = filename.substr (position,
72  filename.size () - position);
73  madara::utility::lower (extension);
74 
75  // do we have a text-based file
76  if (is_string_type (read_as_type) ||
77  extension == ".txt" || extension == ".xml")
78  {
79  add_zero_char = true;
80  }
81 
82  // read the file into the temporary buffer
83  if (madara::utility::read_file (filename, buffer, size, add_zero_char) == 0)
84  {
85  // do we have a text-based file
86  if (is_string_type (read_as_type)
87  || extension == ".txt" || extension == ".xml")
88  {
89  // change the string value and size to appropriate values
90  str_value_ = std::make_shared<std::string> ((char *)buffer, size-1);
91 
92  if (is_string_type (read_as_type))
93  type_ = read_as_type;
94  else if (extension == ".xml")
95  type_ = XML;
96  else
97  type_ = TEXT_FILE;
98  }
99  else
100  {
101  unsigned char *ucbuf = (unsigned char *)buffer;
102  emplace_file (ucbuf, ucbuf + size);
103 
104  if (extension == ".jpg" || read_as_type == IMAGE_JPEG)
105  type_ = IMAGE_JPEG;
106  else
108  }
109 
110  return 0;
111  }
112  else
113  return -1;
114 }
115 
119 ssize_t
120 KnowledgeRecord::to_file (const std::string & filename) const
121 {
122  if (is_string_type ())
123  {
124  return madara::utility::write_file (filename,
125  (void *)str_value_->c_str (), str_value_->size ());
126  }
127  else if (is_binary_file_type ())
128  {
129  return madara::utility::write_file (filename,
130  (void *)&file_value_->at(0), file_value_->size ());
131  }
132  else
133  {
134  std::string buffer (to_string ());
135 
136  return madara::utility::write_file (filename,
137  (void *)buffer.c_str (), buffer.size ());
138  }
139 }
140 
141 
142 double
144 {
145  double value = 0;
146 
147  if (type_ == DOUBLE)
148  value = double_value_;
149  else if (type_ == DOUBLE_ARRAY)
150  value = double_array_->size () == 0 ? 0 : double_array_->at(0);
151  else if (type_ != EMPTY)
152  {
153  std::stringstream buffer;
154 
155  // read the value_ into a stringstream and then convert it to double
156  if (type_ == INTEGER)
157  buffer << int_value_;
158  else if (type_ == INTEGER_ARRAY)
159  buffer << (int_array_->size () == 0 ? 0 : int_array_->at(0));
160  else if (is_string_type ())
161  buffer << str_value_->c_str ();
162 
163  buffer >> value;
164  }
165 
166  return value;
167 }
168 
171 {
172  Integer value (0);
173 
174  if (type_ == INTEGER)
175  value = int_value_;
176  else if (type_ == INTEGER_ARRAY)
177  value = int_array_->size () == 0 ? 0 : int_array_->at(0);
178  else if (type_ != EMPTY)
179  {
180  std::stringstream buffer;
181 
182  // read the value_ into a stringstream and then convert it to double
183  if (type_ == DOUBLE)
184  buffer << double_value_;
185  else if (type_ == DOUBLE_ARRAY)
186  buffer << (double_array_->size () == 0 ? 0 : double_array_->at(0));
187  else if (is_string_type ())
188  buffer << str_value_->c_str();
189 
190  buffer >> value;
191  }
192 
193  return value;
194 }
195 
196 std::vector <KnowledgeRecord::Integer>
198 {
199  std::vector <Integer> integers;
200 
201  if (type_ == EMPTY) {
202  return integers;
203  }
204 
205  unsigned int size = (unsigned int)this->size ();
206  integers.resize (size);
207 
208  if (type_ == INTEGER)
209  {
210  integers[0] = int_value_;
211  }
212  else if (type_ == INTEGER_ARRAY)
213  {
214  const Integer * ptr_temp = &(*int_array_)[0];
215 
216  for (unsigned int i = 0; i < size; ++i)
217  integers[i] = ptr_temp[i];
218  }
219  else if (type_ == DOUBLE)
220  integers[0] = Integer (double_value_);
221  else if (type_ == DOUBLE_ARRAY)
222  {
223  const double * ptr_temp = &(*double_array_)[0];
224 
225  for (unsigned int i = 0; i < size; ++i)
226  integers[i] = Integer (ptr_temp[i]);
227  }
228  else if (is_string_type ())
229  {
230  const char * ptr_temp = str_value_->c_str ();
231 
232  for (unsigned int i = 0; i < size; ++i)
233  integers[i] = Integer (ptr_temp[i]);
234  }
235  else if (is_binary_file_type ())
236  {
237  const unsigned char * ptr_temp = &(*file_value_)[0];
238 
239  for (unsigned int i = 0; i < size; ++i)
240  integers[i] = Integer (ptr_temp[i]);
241  }
242 
243  return integers;
244 }
245 
246 std::vector <double>
248 {
249  std::vector <double> doubles;
250 
251  if (type_ == EMPTY) {
252  return doubles;
253  }
254 
255  unsigned int size = (unsigned int)this->size ();
256  doubles.resize (size);
257 
258  if (type_ == INTEGER)
259  doubles[0] = double (int_value_);
260  else if (type_ == INTEGER_ARRAY)
261  {
262  const Integer * ptr_temp = &(*int_array_)[0];
263 
264  for (unsigned int i = 0; i < size; ++i)
265  doubles[i] = double (ptr_temp[i]);
266  }
267  else if (type_ == DOUBLE)
268  doubles[0] = double_value_;
269  else if (type_ == DOUBLE_ARRAY)
270  {
271  const double * ptr_temp = &(*double_array_)[0];
272 
273  for (unsigned int i = 0; i < size; ++i)
274  doubles[i] = ptr_temp[i];
275  }
276  else if (is_string_type ())
277  {
278  const char * ptr_temp = str_value_->c_str ();
279 
280  for (unsigned int i = 0; i < size; ++i)
281  doubles[i] = double (ptr_temp[i]);
282  }
283  else if (is_binary_file_type ())
284  {
285  const unsigned char * ptr_temp = &(*file_value_)[0];
286 
287  for (unsigned int i = 0; i < size; ++i)
288  doubles[i] = double (ptr_temp[i]);
289  }
290 
291  return doubles;
292 }
293 
294 // read the value_ in a string format
296 KnowledgeRecord::to_string (const std::string & delimiter) const
297 {
298  if (type_ == EMPTY) {
299  return "";
300  }
301 
302  if (!is_string_type ())
303  {
304  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
305  " type_ is %d\n", type_);
306 
307  std::stringstream buffer;
308 
309  if (type_ == INTEGER)
310  buffer << int_value_;
311  else if (type_ == INTEGER_ARRAY)
312  {
313  const Integer * ptr_temp = &(*int_array_)[0];
314  uint32_t size = this->size ();
315 
316  if (size >= 1)
317  buffer << *ptr_temp;
318 
319  ++ptr_temp;
320 
321  for (uint32_t i = 1; i < size; ++i, ++ptr_temp)
322  buffer << delimiter << *ptr_temp;
323  }
324  else if (type_ == DOUBLE)
325  {
326  // set fixed or scientific
327  if (!madara_use_scientific)
328  {
330  "KnowledgeRecord::to_string: using fixed format\n");
331 
332  buffer << std::fixed;
333  }
334  else
335  {
337  "KnowledgeRecord::to_string: using scientific format\n");
338 
339  buffer << std::scientific;
340  }
341 
342  if (madara_double_precision >= 0)
343  {
344  // set the precision of double output
345  buffer << std::setprecision (madara_double_precision);
346 
347  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
348  " precision set to %d\n", madara_double_precision);
349  }
350  else
351  {
352  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
353  " precision set to default\n", madara_double_precision);
354  }
355 
356  buffer << double_value_;
357  }
358  else if (type_ == DOUBLE_ARRAY)
359  {
360  // set fixed or scientific
361  if (!madara_use_scientific)
362  {
364  "KnowledgeRecord::to_string: using fixed format\n");
365 
366  buffer << std::fixed;
367  }
368  else
369  {
371  "KnowledgeRecord::to_string: using scientific format\n");
372 
373  buffer << std::scientific;
374  }
375 
376  if (madara_double_precision >= 0)
377  {
378  buffer << std::setprecision (madara_double_precision);
379 
380  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
381  " precision set to %d\n", madara_double_precision);
382  }
383  else
384  {
385  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
386  " precision set to default\n", madara_double_precision);
387  }
388 
389  const double * ptr_temp = &(*double_array_)[0];
390  uint32_t size = this->size ();
391 
392  if (size >= 1)
393  buffer << *ptr_temp;
394 
395  ++ptr_temp;
396 
397  for (uint32_t i = 1; i < size; ++i, ++ptr_temp)
398  buffer << delimiter << *ptr_temp;
399  }
400  else if (is_binary_file_type ())
401  {
402  buffer << "binary:size=";
403  buffer << size ();
404  }
405  return buffer.str ();
406  }
407  else
408  return std::string (*str_value_);
409 }
410 
411 // read the value_ in a string format
412 unsigned char *
414 {
415  char * buffer;
416 
417  if (is_string_type ())
418  {
419  size = str_value_->size ();
420  buffer = new char [size];
421  memcpy (buffer, str_value_->c_str (), size);
422  }
423  else if (is_binary_file_type ())
424  {
425  size = file_value_-> size();
426  buffer = new char [size];
427  memcpy (buffer, &(*file_value_)[0], size);
428  }
429  else if (type_ == INTEGER)
430  {
431  size = sizeof(Integer);
432  buffer = new char [size];
433  memcpy (buffer, &int_value_, size);
434  }
435  else if (type_ == DOUBLE)
436  {
437  size = sizeof(double);
438  buffer = new char [size];
439  memcpy (buffer, &double_value_, size);
440  }
441  else if (type_ == INTEGER_ARRAY)
442  {
443  size = sizeof(Integer) * int_array_->size ();
444  buffer = new char [size];
445  memcpy (buffer, &(*int_array_)[0], size);
446  }
447  else if (type_ == DOUBLE_ARRAY)
448  {
449  size = sizeof(double) * double_array_->size () ;
450  buffer = new char [size];
451  memcpy (buffer, &(*double_array_)[0], size);
452  } else {
453  buffer = nullptr;
454  size = 0;
455  }
456 
457  return (unsigned char *)buffer;
458 }
459 
460 
462 KnowledgeRecord::fragment (unsigned int first, unsigned int last)
463 {
465 
466  if (is_string_type ())
467  {
468  unsigned int size = (unsigned int)str_value_->size ();
469 
470  // make sure last is accessible in the data type
471  last = std::min <unsigned int> (last, size - 1);
472 
473  // Create a new buffer, copy over the elements, and add a null delimiter
474  char * new_buffer = new char [last - first + 2];
475 
476  memcpy (new_buffer, str_value_->c_str () + first, last - first + 1);
477  new_buffer[last-first + 1] = 0;
478 
479  ret.set_value (new_buffer);
480  }
481  else if (is_binary_file_type ())
482  {
483  unsigned int size = (unsigned int)file_value_->size ();
484 
485  // make sure last is accessible in the data type
486  last = std::min <unsigned int> (last, (unsigned int)size - 1);
487 
488  // Unlike string types, file buffers are not ended with a null delimiter
489  uint32_t bufsize = last - first + 1;
490  unsigned char * new_buffer = new unsigned char [bufsize];
491 
492  memcpy (new_buffer, &(*file_value_)[0] + first, last - first + 1);
493 
494  // create a new record with the unsigned char buffer as contents
495  ret.set_file (new_buffer, bufsize);
496  }
497  else if (type_ == INTEGER_ARRAY)
498  {
499  unsigned int size = (unsigned int)int_array_->size ();
500 
501  // make sure last is accessible in the data type
502  last = std::min <unsigned int> (last, size - 1);
503  uint32_t bufsize = last - first + 1;
504 
505  std::vector <Integer> integers;
506  integers.resize (bufsize);
507  Integer * ptr_temp = &(*int_array_)[0];
508 
509  for (unsigned int i = first; i <= last; ++i, ++ptr_temp)
510  integers[i] = *ptr_temp;
511 
512  ret.set_value (integers);
513  }
514  else if (type_ == DOUBLE_ARRAY)
515  {
516  unsigned int size = (unsigned int) double_array_->size ();
517 
518  // make sure last is accessible in the data type
519  last = std::min <unsigned int> (last, size - 1);
520  uint32_t bufsize = last - first + 1;
521 
522  std::vector <double> doubles;
523  doubles.resize (bufsize);
524  double * ptr_temp = &(*double_array_)[0];
525 
526  for (unsigned int i = first; i <= last; ++i, ++ptr_temp)
527  doubles[i] = *ptr_temp;
528 
529  ret.set_value (doubles);
530  }
531 
532  return ret;
533 }
534 
535 bool
537  const knowledge::KnowledgeRecord & rhs) const
538 {
539  Integer result (0);
540 
541  // if the left hand side is an integer
542  if (is_integer_type ())
543  {
544  Integer lhs = this->to_integer ();
545 
546  if (rhs.is_double_type () || rhs.is_string_type ())
547  {
548  double other = rhs.to_double ();
549 
550  result = lhs < other;
551  }
552  else if (rhs.is_integer_type ())
553  {
554  Integer other = rhs.to_integer ();
555 
556  result = lhs < other;
557  }
558  }
559 
560  // if the left hand side is a string
561  else if (is_string_type ())
562  {
563  // string to string comparison
564  if (rhs.is_string_type ())
565  {
566  result =
567  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
568  size () >= rhs.size () ? size () : rhs.size ()) < 0;
569  }
570 
571  // string to double comparison
572  else if (rhs.is_double_type ())
573  {
574  // when comparing strings to anything else, convert the
575  // value into a double for maximum precision
576  double temp = to_double ();
577  double other = rhs.to_double ();
578 
579  result = temp < other;
580  }
581 
582  // default is string to integer comparison
583  else if (rhs.is_integer_type ())
584  {
585  // when comparing strings to anything else, convert the
586  // value into a double for maximum precision
587  Integer temp = to_integer ();
588  Integer other = rhs.to_integer ();
589 
590  result = temp < other;
591  }
592  }
593 
594  // if the left hand side is a double
595  else if (is_double_type ())
596  {
597  double lhs = to_double ();
598 
599  // string to string comparison
600  if (rhs.is_string_type () || rhs.is_double_type ())
601  {
602  // when comparing strings to anything else, convert the
603  // value into a double for maximum precision
604 
605  double other = rhs.to_double ();
606 
607  result = lhs < other;
608  }
609 
610  // default is string to integer comparison
611  else if (rhs.is_integer_type ())
612  {
613  Integer other = rhs.to_integer ();
614  result = lhs < other;
615  }
616  }
617 
618  return result != 0;
619 }
620 
621 bool
623  const knowledge::KnowledgeRecord & rhs) const
624 {
625  Integer result (0);
626 
627  // if the left hand side is an integer
628  if (is_integer_type ())
629  {
630  Integer lhs = this->to_integer ();
631 
632  if (rhs.is_double_type () || rhs.is_string_type ())
633  {
634  double other = rhs.to_double ();
635 
636  result = lhs <= other;
637  }
638  else if (rhs.is_integer_type ())
639  {
640  Integer other = rhs.to_integer ();
641 
642  result = lhs <= other;
643  }
644  }
645 
646  // if the left hand side is a string
647  else if (is_string_type ())
648  {
649  // string to string comparison
650  if (rhs.is_string_type ())
651  {
652  result =
653  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
654  size () >= rhs.size () ? size () : rhs.size ()) <= 0;
655  }
656 
657  // string to double comparison
658  else if (rhs.is_double_type ())
659  {
660  // when comparing strings to anything else, convert the
661  // value into a double for maximum precision
662  double temp = to_double ();
663  double other = rhs.to_double ();
664 
665  result = temp <= other;
666  }
667 
668  // default is string to integer comparison
669  else if (rhs.is_integer_type ())
670  {
671  // when comparing strings to anything else, convert the
672  // value into a double for maximum precision
673  Integer temp = to_integer ();
674  Integer other = rhs.to_integer ();
675 
676  result = temp <= other;
677  }
678  }
679 
680  // if the left hand side is a double
681  else if (is_double_type ())
682  {
683  double lhs = to_double ();
684 
685  // string to string comparison
686  if (rhs.is_string_type () || rhs.is_double_type ())
687  {
688  // when comparing strings to anything else, convert the
689  // value into a double for maximum precision
690 
691  double other = rhs.to_double ();
692 
693  result = lhs <= other;
694  }
695 
696  // default is string to integer comparison
697  else if (rhs.is_integer_type ())
698  {
699  Integer other = rhs.to_integer ();
700  result = lhs <= other;
701  }
702  }
703 
704  return result != 0;
705 }
706 
707 bool
709  const knowledge::KnowledgeRecord & rhs) const
710 {
711  Integer result (0);
712 
713  // if left hand side does
714  if (!exists ())
715  {
716  if (!rhs.exists () || rhs.is_false ())
717  {
718  result = 1;
719  }
720  }
721 
722  // if the left hand side is an integer
723  else if (is_integer_type ())
724  {
725  if (rhs.is_double_type ())
726  {
727  result = to_double () == rhs.to_double ();
728  }
729  else if (rhs.is_integer_type ())
730  {
731  result = to_integer () == rhs.to_integer ();
732  }
733  else if (rhs.is_string_type ())
734  {
735  if (rhs.size () > 0 && rhs.str_value_->at (0) >= '0' &&
736  rhs.str_value_->at (0) <= '9')
737  {
738  result = to_double () == rhs.to_double ();
739  }
740  else result = 0;
741  }
742  }
743 
744  // if the left hand side is a string
745  else if (is_string_type ())
746  {
747  // string to string comparison
748  if (rhs.is_string_type ())
749  {
750  result =
751  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
752  size () >= rhs.size () ? size () : rhs.size ()) == 0;
753  }
754 
755  // string to double comparison
756  else if (rhs.is_double_type ())
757  {
758  // when comparing strings to anything else, convert the
759  // value into a double for maximum precision
760  result = to_double () == rhs.to_double ();
761  }
762 
763  // check if right hand side is uncreated
764  else if (!rhs.exists ())
765  {
766  result = is_false ();
767  }
768 
769  // default is string to integer comparison
770  else if (rhs.is_integer_type ())
771  {
772  if (size () > 0 && this->str_value_->at (0) >= '0' &&
773  this->str_value_->at (0) <= '9')
774  {
775  result = to_double () == rhs.to_double ();
776  }
777  else
778  {
779  result = 0;
780  }
781  }
782  }
783 
784  // if the left hand side is a double
785  else if (is_double_type ())
786  {
787  double lhs = to_double ();
788 
789  // string to string comparison
790  if (rhs.is_string_type () || rhs.is_double_type ())
791  {
792  // when comparing strings to anything else, convert the
793  // value into a double for maximum precision
794 
795  double other = rhs.to_double ();
796 
797  result = lhs == other;
798  }
799 
800  // default is string to integer comparison
801  else if (rhs.is_integer_type ())
802  {
803  Integer other = rhs.to_integer ();
804 
805  result = lhs == other;
806  }
807  }
808 
809  return result != 0;
810 }
811 
812 bool
814 {
815  Integer result (0);
816 
817  // if the left hand side is an integer
818  if (is_integer_type ())
819  {
820  Integer lhs = this->to_integer ();
821 
822  if (rhs.is_double_type () || rhs.is_string_type ())
823  {
824  double other = rhs.to_double ();
825 
826  result = lhs > other;
827  }
828  else if (rhs.is_integer_type ())
829  {
830  Integer other = rhs.to_integer ();
831 
832  result = lhs > other;
833  }
834  }
835 
836 
837  // if the left hand side is a string
838  else if (is_string_type ())
839  {
840  // string to string comparison
841  if (rhs.is_string_type ())
842  {
843  result =
844  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
845  size () >= rhs.size () ? size () : rhs.size ()) > 0;
846  }
847 
848  // string to double comparison
849  else if (rhs.is_double_type ())
850  {
851  // when comparing strings to anything else, convert the
852  // value into a double for maximum precision
853  double lhs = to_double ();
854  double other = rhs.to_double ();
855 
856  result = lhs > other;
857  }
858 
859  // default is string to integer comparison
860  else if (rhs.is_integer_type ())
861  {
862  // when comparing strings to anything else, convert the
863  // value into a double for maximum precision
864  Integer lhs = to_integer ();
865  Integer other = rhs.to_integer ();
866 
867  result = lhs > other;
868  }
869  }
870 
871  // if the left hand side is a double
872  else if (is_double_type ())
873  {
874  double lhs = to_double ();
875 
876  // string to string comparison
877  if (rhs.is_string_type () || rhs.is_double_type ())
878  {
879  // when comparing strings to anything else, convert the
880  // value into a double for maximum precision
881 
882  double other = rhs.to_double ();
883 
884  result = lhs > other;
885  }
886 
887  // default is string to integer comparison
888  else if (rhs.is_integer_type ())
889  {
890  Integer other = rhs.to_integer ();
891 
892  result = lhs > other;
893  }
894  }
895 
896  return result != 0;
897 }
898 
899 bool
901 {
902  Integer result (0);
903 
904  // if the left hand side is an integer
905  if (is_integer_type ())
906  {
907  Integer lhs = this->to_integer ();
908 
909  if (rhs.is_double_type () || rhs.is_string_type ())
910  {
911  double other = rhs.to_double ();
912 
913  result = lhs >= other;
914  }
915  else if (rhs.is_integer_type ())
916  {
917  Integer other = rhs.to_integer ();
918 
919  result = lhs >= other;
920  }
921  }
922 
923 
924  // if the left hand side is a string
925  else if (is_string_type ())
926  {
927  // string to string comparison
928  if (rhs.is_string_type ())
929  {
930  result =
931  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
932  size () >= rhs.size () ? size () : rhs.size ()) >= 0;
933  }
934 
935  // string to double comparison
936  else if (rhs.is_double_type ())
937  {
938  // when comparing strings to anything else, convert the
939  // value into a double for maximum precision
940  double lhs = to_double ();
941  double other = rhs.to_double ();
942 
943  result = lhs >= other;
944  }
945 
946  // default is string to integer comparison
947  else if (rhs.is_integer_type ())
948  {
949  // when comparing strings to anything else, convert the
950  // value into a double for maximum precision
951  Integer lhs = to_integer ();
952  Integer other = rhs.to_integer ();
953 
954  result = lhs >= other;
955  }
956  }
957 
958  // if the left hand side is a double
959  else if (is_double_type ())
960  {
961  double lhs = to_double ();
962 
963  // string to string comparison
964  if (rhs.is_string_type () || rhs.is_double_type ())
965  {
966  // when comparing strings to anything else, convert the
967  // value into a double for maximum precision
968 
969  double other = rhs.to_double ();
970 
971  result = lhs >= other;
972  }
973 
974  // default is string to integer comparison
975  else if (rhs.is_integer_type ())
976  {
977  Integer other = rhs.to_integer ();
978 
979  result = lhs >= other;
980  }
981  }
982 
983  return result != 0;
984 }
985 
986 
989 {
990  knowledge::KnowledgeRecord ret_value;
991 
992  if (type_ == INTEGER_ARRAY)
993  {
994  if (index < size_t (int_array_->size ()))
995  ret_value.set_value (int_array_->at (index));
996  }
997  else if (type_ == DOUBLE_ARRAY)
998  {
999  if (index < size_t (double_array_-> size ()))
1000  ret_value.set_value (double_array_->at (index));
1001  }
1002 
1003  return ret_value;
1004 }
1005 
1008 {
1009  if (type_ == DOUBLE_ARRAY)
1010  {
1011  unshare();
1012 
1013  if (double_array_->size () <= index) {
1014  double_array_->resize (index + 1);
1015  }
1016  return knowledge::KnowledgeRecord(--double_array_->at (index));
1017  }
1018  else if (type_ == INTEGER_ARRAY)
1019  {
1020  unshare();
1021 
1022  if (int_array_->size () <= index) {
1023  int_array_->resize (index + 1);
1024  }
1025  return knowledge::KnowledgeRecord(--int_array_->at (index));
1026  }
1027  std::vector<Integer> tmp(index + 1);
1028  emplace_integers (std::move(tmp));
1029  return knowledge::KnowledgeRecord(--int_array_->at (index));
1030 }
1031 
1034 {
1035  if (type_ == DOUBLE_ARRAY)
1036  {
1037  unshare();
1038 
1039  if (double_array_->size () <= index) {
1040  double_array_->resize (index + 1);
1041  }
1042  return knowledge::KnowledgeRecord(++double_array_->at (index));
1043  }
1044  else if (type_ == INTEGER_ARRAY)
1045  {
1046  unshare();
1047 
1048  if (int_array_->size () <= index) {
1049  int_array_->resize (index + 1);
1050  }
1051  return knowledge::KnowledgeRecord(++int_array_->at (index));
1052  }
1053  std::vector<Integer> tmp(index + 1);
1054  emplace_integers (std::move(tmp));
1055  return knowledge::KnowledgeRecord(++int_array_->at (index));
1056 }
1057 
1058 void
1059 KnowledgeRecord::resize (size_t new_size)
1060 {
1061  size_t cur_size = size ();
1062 
1063  if (cur_size == new_size) {
1064  return;
1065  }
1066 
1067  unshare();
1068 
1069  if (new_size > cur_size)
1070  {
1071  if (type_ == EMPTY ||
1072  type_ == INTEGER)
1073  {
1074  Integer zero (0);
1075  set_index (new_size - 1, zero);
1076  return;
1077  }
1078  else if (type_ == DOUBLE)
1079  {
1080  double zero (0.0);
1081  set_index (new_size - 1, zero);
1082  return;
1083  }
1084  }
1085  if (type_ == INTEGER_ARRAY) {
1086  int_array_->resize (new_size);
1087  } else if (type_ == DOUBLE_ARRAY) {
1088  double_array_->resize (new_size);
1089  } else if (is_string_type (type_)) {
1090  str_value_->resize (new_size);
1091  } else if (is_binary_file_type (type_)) {
1092  file_value_->resize (new_size);
1093  }
1094 }
1095 
1096 int
1098  ThreadSafeContext & context,
1099  const std::string & key, unsigned int /*quality*/, uint64_t /*clock*/,
1100  bool perform_lock)
1101 {
1102  int result = -1;
1103 
1104  if (key.length () > 0)
1105  {
1106  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1107  " attempting to set %s=%s\n", key.c_str (), to_string ().c_str ());
1108 
1109  if (perform_lock)
1110  context.lock ();
1111 
1112  // if the data we are updating had a lower clock value or less quality
1113  // then that means this update is the latest value. Among
1114  // other things, this means our solution will work even
1115  // without FIFO channel transports
1116 
1117  // if the data we are updating had a lower clock value
1118  // then that means this update is the latest value. Among
1119  // other things, this means our solution will work even
1120  // without FIFO channel transports
1121  result = context.update_record_from_external (key, *this,
1123 
1124  if (perform_lock)
1125  {
1126  context.unlock ();
1127  context.set_changed ();
1128  }
1129 
1130  // if we actually updated the value
1131  if (result == 1)
1132  {
1133  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1134  " received data[%s]=%s.\n",
1135  key.c_str (), to_string ().c_str ());
1136  }
1137  // if the data was already current
1138  else if (result == 0)
1139  {
1140  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1141  " discarded data[%s]=%s as the value was already set.\n",
1142  key.c_str (), to_string ().c_str ());
1143  }
1144  else if (result == -1)
1145  {
1146  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1147  " discarded data due to null key.\n");
1148  }
1149  else if (result == -2)
1150  {
1151  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1152  " discarded data[%s]=%s due to lower quality.\n",
1153  key.c_str (), to_string ().c_str ());
1154  }
1155  else if (result == -3)
1156  {
1157  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1158  " discarded data[%s]=%" PRId64 " due to older timestamp.\n",
1159  key.c_str (), to_string ().c_str ());
1160  }
1161  }
1162  return result;
1163 }
1164 
1165 bool
1167 {
1168  madara_logger_ptr_log (logger_, logger::LOG_MAJOR, "KnowledgeRecord::apply:" \
1169  " checking if record is non-zero.\n");
1170 
1171  if (is_integer_type ())
1172  return to_integer () != 0;
1173  else if (is_double_type ())
1174  {
1175  double value = to_double ();
1176  return value < 0 || value > 0;
1177  }
1178  else if (is_string_type ())
1179  {
1180  return str_value_->size () >= 1;
1181  }
1182  else if (is_binary_file_type ())
1183  {
1184  return file_value_->size () >= 1;
1185  }
1186  else
1187  {
1188  return false;
1189  }
1190 }
1191 
1192 } }
1193 
1194 #endif // _KNOWLEDGE_RECORD_CPP_
This class encapsulates an entry in a KnowledgeBase.
int apply(madara::knowledge::ThreadSafeContext &context, const std::string &key, unsigned int quality, uint64_t clock, bool perform_lock)
Apply the knowledge record to a context, given some quality and clock.
bool is_true(void) const
Checks to see if the record is true.
int update_record_from_external(const std::string &key, const knowledge::KnowledgeRecord &rhs, const KnowledgeUpdateSettings &settings=KnowledgeUpdateSettings(true))
Atomically sets if the variable value meets update conditions.
static void set_fixed(void)
Sets the output format for doubles to std::fixed.
void emplace_integers(Args &&...args)
Construct a vector of integers within this KnowledgeRecord.
madara::knowledge::KnowledgeRecord KnowledgeRecord
void emplace_file(Args &&...args)
Construct a file (vector of unsigned char) within this KnowledgeRecord.
int read_file(const std::string &filename, void *&buffer, size_t &size, bool add_zero_char)
Reads a file into a provided void pointer.
Definition: Utility.cpp:480
double to_double(void) const
converts the value to a float/double.
KnowledgeRecord inc_index(size_t index)
increments the value at the index to the specified value.
void set_file(const unsigned char *new_value, size_t size)
sets the value to an unknown file type
void lock(void) const
Locks the mutex on this context.
void clear_value(void) noexcept
clears any dynamic values.
bool is_binary_file_type(void) const
returns true if the knowledge record has a binary file type
ssize_t to_file(const std::string &filename) const
writes the value to a file
This class stores variables and their values for use by any entity needing state information in a thr...
KnowledgeRecord fragment(unsigned int first, unsigned int last)
returns a record containing a fragment of the character buffer.
std::shared_ptr< std::vector< Integer > > int_array_
std::string & lower(std::string &input)
Converts the string to lower.
Definition: Utility.inl:87
MADARA_EXPORT utility::Refcounter< logger::Logger > global_logger
bool exists(void) const
Checks if record exists (i.e., is not uncreated)
bool is_double_type(void) const
returns if the record is a double type (DOUBLE, DOUBLE_ARRAY)
logger::Logger * logger_
the logger used for any internal debugging information
bool operator>(const KnowledgeRecord &rhs) const
Greater than.
static struct madara::knowledge::tags::doubles_t doubles
bool operator>=(const KnowledgeRecord &rhs) const
Greater than or equal to.
void set_value(const KnowledgeRecord &new_value)
Sets the value from another KnowledgeRecord, does not copy clock and write_quality.
static struct madara::knowledge::tags::string_t string
bool operator==(const KnowledgeRecord &rhs) const
Equal to.
#define madara_logger_ptr_log(logger, level,...)
Fast version of the madara::logger::log method for Logger pointers.
Definition: Logger.h:32
void unlock(void) const
Unlocks the mutex on this context.
std::vector< double > to_doubles(void) const
converts the value to a vector of doubles
static void set_precision(int new_precision)
Sets the double precision of a double record when using to_string ().
std::shared_ptr< std::vector< double > > double_array_
void set_index(size_t index, T value)
sets the value at the index to the specified value.
Integer to_integer(void) const
converts the value to an integer.
static struct madara::knowledge::tags::integers_t integers
static const KnowledgeUpdateSettings GLOBAL_AS_LOCAL_NO_EXPAND
std::shared_ptr< std::vector< unsigned char > > file_value_
void set_changed(void)
Force a change to be registered, waking up anyone waiting on entry.
bool operator<(const KnowledgeRecord &rhs) const
Less than.
static void set_scientific(void)
Sets the output format for doubles to std::scientific.
void unshare(void)
If this record holds a shared_ptr, make a copy of the underlying value so it has an exclusive copy...
std::vector< Integer > to_integers(void) const
converts the value to a vector of integers
Provides functions and classes for the distributed knowledge base.
uint32_t type_
type of variable (INTEGER, DOUBLE, STRING, FILE, IMAGE)
KnowledgeRecord dec_index(size_t index)
decrements the value at the index to the specified value.
bool operator<=(const KnowledgeRecord &rhs) const
Less than or equal to.
Copyright (c) 2015 Carnegie Mellon University.
KnowledgeRecord retrieve_index(size_t index) const
retrieves the value at an array index.
int read_file(const std::string &filename, uint32_t read_as_type=0)
reads a file and sets the type appropriately according to the extension
bool is_integer_type(void) const
returns if the record is a integer type (INTEGER, INTEGER_ARRAY)
bool is_false(void) const
Checks to see if the record is false.
bool is_string_type(void) const
returns true if the record is a string type (STRING, XML, TEXT_FILE)
std::string to_string(const std::string &delimiter=", ") const
converts the value to a string.
void resize(size_t new_size)
resizes an array to a new size
ssize_t write_file(const std::string &filename, void *buffer, size_t size)
Writes a file with provided contents.
Definition: Utility.cpp:547
uint32_t size(void) const
returns the size of the value
std::shared_ptr< std::string > str_value_
unsigned char * to_unmanaged_buffer(size_t &size) const
returns an unmanaged buffer that the user will have to take care of (this is a copy of the internal v...
static int get_precision(void)
Gets the current double precision for double to string conversion.