MADARA  3.1.8
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);
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_->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_->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_->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_->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  integers.push_back(0);
203  return integers;
204  }
205 
206  unsigned int size = (unsigned int)this->size ();
207  integers.resize (size);
208 
209  if (type_ == INTEGER)
210  {
211  integers[0] = int_value_;
212  }
213  else if (type_ == INTEGER_ARRAY)
214  {
215  const Integer * ptr_temp = &(*int_array_)[0];
216 
217  for (unsigned int i = 0; i < size; ++i)
218  integers[i] = ptr_temp[i];
219  }
220  else if (type_ == DOUBLE)
221  integers[0] = Integer (double_value_);
222  else if (type_ == DOUBLE_ARRAY)
223  {
224  const double * ptr_temp = &(*double_array_)[0];
225 
226  for (unsigned int i = 0; i < size; ++i)
227  integers[i] = Integer (ptr_temp[i]);
228  }
229  else if (is_string_type ())
230  {
231  const char * ptr_temp = str_value_->c_str ();
232 
233  for (unsigned int i = 0; i < size; ++i)
234  integers[i] = Integer (ptr_temp[i]);
235  }
236  else if (is_binary_file_type ())
237  {
238  const unsigned char * ptr_temp = &(*file_value_)[0];
239 
240  for (unsigned int i = 0; i < size; ++i)
241  integers[i] = Integer (ptr_temp[i]);
242  }
243 
244  return integers;
245 }
246 
247 std::vector <double>
249 {
250  std::vector <double> doubles;
251 
252  if (type_ == EMPTY) {
253  doubles.push_back(0);
254  return doubles;
255  }
256 
257  unsigned int size = (unsigned int)this->size ();
258  doubles.resize (size);
259 
260  if (type_ == INTEGER)
261  doubles[0] = double (int_value_);
262  else if (type_ == INTEGER_ARRAY)
263  {
264  const Integer * ptr_temp = &(*int_array_)[0];
265 
266  for (unsigned int i = 0; i < size; ++i)
267  doubles[i] = double (ptr_temp[i]);
268  }
269  else if (type_ == DOUBLE)
270  doubles[0] = double_value_;
271  else if (type_ == DOUBLE_ARRAY)
272  {
273  const double * ptr_temp = &(*double_array_)[0];
274 
275  for (unsigned int i = 0; i < size; ++i)
276  doubles[i] = ptr_temp[i];
277  }
278  else if (is_string_type ())
279  {
280  const char * ptr_temp = str_value_->c_str ();
281 
282  for (unsigned int i = 0; i < size; ++i)
283  doubles[i] = double (ptr_temp[i]);
284  }
285  else if (is_binary_file_type ())
286  {
287  const unsigned char * ptr_temp = &(*file_value_)[0];
288 
289  for (unsigned int i = 0; i < size; ++i)
290  doubles[i] = double (ptr_temp[i]);
291  }
292 
293  return doubles;
294 }
295 
296 // read the value_ in a string format
298 KnowledgeRecord::to_string (const std::string & delimiter) const
299 {
300  if (type_ == EMPTY) {
301  return "0";
302  }
303 
304  if (!is_string_type ())
305  {
306  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
307  " type_ is %d\n", type_);
308 
309  std::stringstream buffer;
310 
311  if (type_ == INTEGER)
312  buffer << int_value_;
313  else if (type_ == INTEGER_ARRAY)
314  {
315  const Integer * ptr_temp = &(*int_array_)[0];
316  uint32_t size = this->size ();
317 
318  if (size >= 1)
319  buffer << *ptr_temp;
320 
321  ++ptr_temp;
322 
323  for (uint32_t i = 1; i < size; ++i, ++ptr_temp)
324  buffer << delimiter << *ptr_temp;
325  }
326  else if (type_ == DOUBLE)
327  {
328  // set fixed or scientific
329  if (!madara_use_scientific)
330  {
332  "KnowledgeRecord::to_string: using fixed format\n");
333 
334  buffer << std::fixed;
335  }
336  else
337  {
339  "KnowledgeRecord::to_string: using scientific format\n");
340 
341  buffer << std::scientific;
342  }
343 
344  if (madara_double_precision >= 0)
345  {
346  // set the precision of double output
347  buffer << std::setprecision (madara_double_precision);
348 
349  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
350  " precision set to %d\n", madara_double_precision);
351  }
352  else
353  {
354  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
355  " precision set to default\n", madara_double_precision);
356  }
357 
358  buffer << double_value_;
359  }
360  else if (type_ == DOUBLE_ARRAY)
361  {
362  // set fixed or scientific
363  if (!madara_use_scientific)
364  {
366  "KnowledgeRecord::to_string: using fixed format\n");
367 
368  buffer << std::fixed;
369  }
370  else
371  {
373  "KnowledgeRecord::to_string: using scientific format\n");
374 
375  buffer << std::scientific;
376  }
377 
378  if (madara_double_precision >= 0)
379  {
380  buffer << std::setprecision (madara_double_precision);
381 
382  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
383  " precision set to %d\n", madara_double_precision);
384  }
385  else
386  {
387  madara_logger_ptr_log (logger_, logger::LOG_DETAILED, "KnowledgeRecord::to_string:" \
388  " precision set to default\n", madara_double_precision);
389  }
390 
391  const double * ptr_temp = &(*double_array_)[0];
392  uint32_t size = this->size ();
393 
394  if (size >= 1)
395  buffer << *ptr_temp;
396 
397  ++ptr_temp;
398 
399  for (uint32_t i = 1; i < size; ++i, ++ptr_temp)
400  buffer << delimiter << *ptr_temp;
401  }
402  else if (is_binary_file_type ())
403  {
404  buffer << "binary:size=";
405  buffer << size ();
406  }
407  return buffer.str ();
408  }
409  else
410  return std::string (*str_value_);
411 }
412 
413 // read the value_ in a string format
414 unsigned char *
416 {
417  char * buffer;
418 
419  if (is_string_type ())
420  {
421  size = str_value_->size ();
422  buffer = new char [size];
423  memcpy (buffer, str_value_->c_str (), size);
424  }
425  else if (is_binary_file_type ())
426  {
427  size = file_value_-> size();
428  buffer = new char [size];
429  memcpy (buffer, &(*file_value_)[0], size);
430  }
431  else if (type_ == INTEGER)
432  {
433  size = sizeof(Integer);
434  buffer = new char [size];
435  memcpy (buffer, &int_value_, size);
436  }
437  else if (type_ == DOUBLE)
438  {
439  size = sizeof(double);
440  buffer = new char [size];
441  memcpy (buffer, &double_value_, size);
442  }
443  else if (type_ == INTEGER_ARRAY)
444  {
445  size = sizeof(Integer) * int_array_->size ();
446  buffer = new char [size];
447  memcpy (buffer, &(*int_array_)[0], size);
448  }
449  else if (type_ == DOUBLE_ARRAY)
450  {
451  size = sizeof(double) * double_array_->size () ;
452  buffer = new char [size];
453  memcpy (buffer, &(*double_array_)[0], size);
454  } else {
455  buffer = nullptr;
456  size = 0;
457  }
458 
459  return (unsigned char *)buffer;
460 }
461 
462 
464 KnowledgeRecord::fragment (unsigned int first, unsigned int last)
465 {
467 
468  if (is_string_type ())
469  {
470  size_t size = str_value_->size ();
471 
472  // make sure last is accessible in the data type
473  last = std::min <unsigned int> (last, size - 1);
474 
475  // Create a new buffer, copy over the elements, and add a null delimiter
476  char * new_buffer = new char [last - first + 2];
477 
478  memcpy (new_buffer, str_value_->c_str () + first, last - first + 1);
479  new_buffer[last-first + 1] = 0;
480 
481  ret.set_value (new_buffer);
482  }
483  else if (is_binary_file_type ())
484  {
485  size_t size = file_value_->size ();
486 
487  // make sure last is accessible in the data type
488  last = std::min <unsigned int> (last, size - 1);
489 
490  // Unlike string types, file buffers are not ended with a null delimiter
491  uint32_t bufsize = last - first + 1;
492  unsigned char * new_buffer = new unsigned char [bufsize];
493 
494  memcpy (new_buffer, &(*file_value_)[0] + first, last - first + 1);
495 
496  // create a new record with the unsigned char buffer as contents
497  ret.set_file (new_buffer, bufsize);
498  }
499  else if (type_ == INTEGER_ARRAY)
500  {
501  size_t size = int_array_->size ();
502 
503  // make sure last is accessible in the data type
504  last = std::min <unsigned int> (last, size - 1);
505  uint32_t bufsize = last - first + 1;
506 
507  std::vector <Integer> integers;
508  integers.resize (bufsize);
509  Integer * ptr_temp = &(*int_array_)[0];
510 
511  for (unsigned int i = first; i <= last; ++i, ++ptr_temp)
512  integers[i] = *ptr_temp;
513 
514  ret.set_value (integers);
515  }
516  else if (type_ == DOUBLE_ARRAY)
517  {
518  size_t size = double_array_->size ();
519 
520  // make sure last is accessible in the data type
521  last = std::min <unsigned int> (last, size - 1);
522  uint32_t bufsize = last - first + 1;
523 
524  std::vector <double> doubles;
525  doubles.resize (bufsize);
526  double * ptr_temp = &(*double_array_)[0];
527 
528  for (unsigned int i = first; i <= last; ++i, ++ptr_temp)
529  doubles[i] = *ptr_temp;
530 
531  ret.set_value (doubles);
532  }
533 
534  return ret;
535 }
536 
537 bool
539  const knowledge::KnowledgeRecord & rhs) const
540 {
541  Integer result (0);
542 
543  // if the left hand side is an integer
544  if (is_integer_type ())
545  {
546  Integer lhs = this->to_integer ();
547 
548  if (rhs.is_double_type () || rhs.is_string_type ())
549  {
550  double other = rhs.to_double ();
551 
552  result = lhs < other;
553  }
554  else if (rhs.is_integer_type ())
555  {
556  Integer other = rhs.to_integer ();
557 
558  result = lhs < other;
559  }
560  }
561 
562  // if the left hand side is a string
563  else if (is_string_type ())
564  {
565  // string to string comparison
566  if (rhs.is_string_type ())
567  {
568  result =
569  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
570  size () >= rhs.size () ? size () : rhs.size ()) < 0;
571  }
572 
573  // string to double comparison
574  else if (rhs.is_double_type ())
575  {
576  // when comparing strings to anything else, convert the
577  // value into a double for maximum precision
578  double temp = to_double ();
579  double other = rhs.to_double ();
580 
581  result = temp < other;
582  }
583 
584  // default is string to integer comparison
585  else if (rhs.is_integer_type ())
586  {
587  // when comparing strings to anything else, convert the
588  // value into a double for maximum precision
589  Integer temp = to_integer ();
590  Integer other = rhs.to_integer ();
591 
592  result = temp < other;
593  }
594  }
595 
596  // if the left hand side is a double
597  else if (is_double_type ())
598  {
599  double lhs = to_double ();
600 
601  // string to string comparison
602  if (rhs.is_string_type () || rhs.is_double_type ())
603  {
604  // when comparing strings to anything else, convert the
605  // value into a double for maximum precision
606 
607  double other = rhs.to_double ();
608 
609  result = lhs < other;
610  }
611 
612  // default is string to integer comparison
613  else if (rhs.is_integer_type ())
614  {
615  Integer other = rhs.to_integer ();
616  result = lhs < other;
617  }
618  }
619 
620  return result;
621 }
622 
623 bool
625  const knowledge::KnowledgeRecord & rhs) const
626 {
627  Integer result (0);
628 
629  // if the left hand side is an integer
630  if (is_integer_type ())
631  {
632  Integer lhs = this->to_integer ();
633 
634  if (rhs.is_double_type () || rhs.is_string_type ())
635  {
636  double other = rhs.to_double ();
637 
638  result = lhs <= other;
639  }
640  else if (rhs.is_integer_type ())
641  {
642  Integer other = rhs.to_integer ();
643 
644  result = lhs <= other;
645  }
646  }
647 
648  // if the left hand side is a string
649  else if (is_string_type ())
650  {
651  // string to string comparison
652  if (rhs.is_string_type ())
653  {
654  result =
655  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
656  size () >= rhs.size () ? size () : rhs.size ()) <= 0;
657  }
658 
659  // string to double comparison
660  else if (rhs.is_double_type ())
661  {
662  // when comparing strings to anything else, convert the
663  // value into a double for maximum precision
664  double temp = to_double ();
665  double other = rhs.to_double ();
666 
667  result = temp <= other;
668  }
669 
670  // default is string to integer comparison
671  else if (rhs.is_integer_type ())
672  {
673  // when comparing strings to anything else, convert the
674  // value into a double for maximum precision
675  Integer temp = to_integer ();
676  Integer other = rhs.to_integer ();
677 
678  result = temp <= other;
679  }
680  }
681 
682  // if the left hand side is a double
683  else if (is_double_type ())
684  {
685  double lhs = to_double ();
686 
687  // string to string comparison
688  if (rhs.is_string_type () || rhs.is_double_type ())
689  {
690  // when comparing strings to anything else, convert the
691  // value into a double for maximum precision
692 
693  double other = rhs.to_double ();
694 
695  result = lhs <= other;
696  }
697 
698  // default is string to integer comparison
699  else if (rhs.is_integer_type ())
700  {
701  Integer other = rhs.to_integer ();
702  result = lhs <= other;
703  }
704  }
705 
706  return result;
707 }
708 
709 bool
711  const knowledge::KnowledgeRecord & rhs) const
712 {
713  Integer result (0);
714 
715  // if left hand side does
716  if (!exists ())
717  {
718  if (!rhs.exists () || rhs.is_false ())
719  {
720  result = 1;
721  }
722  }
723 
724  // if the left hand side is an integer
725  else if (is_integer_type ())
726  {
727  Integer lhs = this->to_integer ();
728 
729  if (rhs.is_double_type () || rhs.is_string_type ())
730  {
731  double other = rhs.to_double ();
732 
733  result = lhs == other;
734  }
735  else if (rhs.is_integer_type ())
736  {
737  Integer other = rhs.to_integer ();
738 
739  result = lhs == other;
740  }
741  }
742 
743  // if the left hand side is a string
744  else if (is_string_type ())
745  {
746  // string to string comparison
747  if (rhs.is_string_type ())
748  {
749  result =
750  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
751  size () >= rhs.size () ? size () : rhs.size ()) == 0;
752  }
753 
754  // string to double comparison
755  else if (rhs.is_double_type ())
756  {
757  // when comparing strings to anything else, convert the
758  // value into a double for maximum precision
759  double temp = to_double ();
760  double other = rhs.to_double ();
761 
762  result = temp == other;
763  }
764 
765  // check if right hand side is uncreated
766  else if (!rhs.exists ())
767  {
768  result = is_false ();
769  }
770 
771  // default is string to integer comparison
772  else if (rhs.is_integer_type ())
773  {
774  // when comparing strings to anything else, convert the
775  // value into a double for maximum precision
776  Integer temp = to_integer ();
777  Integer other = rhs.to_integer ();
778 
779  result = temp == other;
780  }
781  }
782 
783  // if the left hand side is a double
784  else if (is_double_type ())
785  {
786  double lhs = to_double ();
787 
788  // string to string comparison
789  if (rhs.is_string_type () || rhs.is_double_type ())
790  {
791  // when comparing strings to anything else, convert the
792  // value into a double for maximum precision
793 
794  double other = rhs.to_double ();
795 
796  result = lhs == other;
797  }
798 
799  // default is string to integer comparison
800  else if (rhs.is_integer_type ())
801  {
802  Integer other = rhs.to_integer ();
803 
804  result = lhs == other;
805  }
806  }
807 
808  return result;
809 }
810 
811 bool
813 {
814  Integer result (0);
815 
816  // if the left hand side is an integer
817  if (is_integer_type ())
818  {
819  Integer lhs = this->to_integer ();
820 
821  if (rhs.is_double_type () || rhs.is_string_type ())
822  {
823  double other = rhs.to_double ();
824 
825  result = lhs > other;
826  }
827  else if (rhs.is_integer_type ())
828  {
829  Integer other = rhs.to_integer ();
830 
831  result = lhs > other;
832  }
833  }
834 
835 
836  // if the left hand side is a string
837  else if (is_string_type ())
838  {
839  // string to string comparison
840  if (rhs.is_string_type ())
841  {
842  result =
843  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
844  size () >= rhs.size () ? size () : rhs.size ()) > 0;
845  }
846 
847  // string to double comparison
848  else if (rhs.is_double_type ())
849  {
850  // when comparing strings to anything else, convert the
851  // value into a double for maximum precision
852  double lhs = to_double ();
853  double other = rhs.to_double ();
854 
855  result = lhs > other;
856  }
857 
858  // default is string to integer comparison
859  else if (rhs.is_integer_type ())
860  {
861  // when comparing strings to anything else, convert the
862  // value into a double for maximum precision
863  Integer lhs = to_integer ();
864  Integer other = rhs.to_integer ();
865 
866  result = lhs > other;
867  }
868  }
869 
870  // if the left hand side is a double
871  else if (is_double_type ())
872  {
873  double lhs = to_double ();
874 
875  // string to string comparison
876  if (rhs.is_string_type () || rhs.is_double_type ())
877  {
878  // when comparing strings to anything else, convert the
879  // value into a double for maximum precision
880 
881  double other = rhs.to_double ();
882 
883  result = lhs > other;
884  }
885 
886  // default is string to integer comparison
887  else if (rhs.is_integer_type ())
888  {
889  Integer other = rhs.to_integer ();
890 
891  result = lhs > other;
892  }
893  }
894 
895  return result;
896 }
897 
898 bool
900 {
901  Integer result (0);
902 
903  // if the left hand side is an integer
904  if (is_integer_type ())
905  {
906  Integer lhs = this->to_integer ();
907 
908  if (rhs.is_double_type () || rhs.is_string_type ())
909  {
910  double other = rhs.to_double ();
911 
912  result = lhs >= other;
913  }
914  else if (rhs.is_integer_type ())
915  {
916  Integer other = rhs.to_integer ();
917 
918  result = lhs >= other;
919  }
920  }
921 
922 
923  // if the left hand side is a string
924  else if (is_string_type ())
925  {
926  // string to string comparison
927  if (rhs.is_string_type ())
928  {
929  result =
930  strncmp (str_value_->c_str (), rhs.str_value_->c_str (),
931  size () >= rhs.size () ? size () : rhs.size ()) >= 0;
932  }
933 
934  // string to double comparison
935  else if (rhs.is_double_type ())
936  {
937  // when comparing strings to anything else, convert the
938  // value into a double for maximum precision
939  double lhs = to_double ();
940  double other = rhs.to_double ();
941 
942  result = lhs >= other;
943  }
944 
945  // default is string to integer comparison
946  else if (rhs.is_integer_type ())
947  {
948  // when comparing strings to anything else, convert the
949  // value into a double for maximum precision
950  Integer lhs = to_integer ();
951  Integer other = rhs.to_integer ();
952 
953  result = lhs >= other;
954  }
955  }
956 
957  // if the left hand side is a double
958  else if (is_double_type ())
959  {
960  double lhs = to_double ();
961 
962  // string to string comparison
963  if (rhs.is_string_type () || rhs.is_double_type ())
964  {
965  // when comparing strings to anything else, convert the
966  // value into a double for maximum precision
967 
968  double other = rhs.to_double ();
969 
970  result = lhs >= other;
971  }
972 
973  // default is string to integer comparison
974  else if (rhs.is_integer_type ())
975  {
976  Integer other = rhs.to_integer ();
977 
978  result = lhs >= other;
979  }
980  }
981 
982  return result;
983 }
984 
985 
988 {
989  knowledge::KnowledgeRecord ret_value;
990 
991  if (type_ == INTEGER_ARRAY)
992  {
993  if (index < size_t (int_array_->size ()))
994  ret_value.set_value (int_array_->at (index));
995  }
996  else if (type_ == DOUBLE_ARRAY)
997  {
998  if (index < size_t (double_array_-> size ()))
999  ret_value.set_value (double_array_->at (index));
1000  }
1001 
1002  return ret_value;
1003 }
1004 
1007 {
1008  if (type_ == DOUBLE_ARRAY)
1009  {
1010  unshare();
1011 
1012  if (double_array_->size () <= index) {
1013  double_array_->resize (index + 1);
1014  }
1015  return knowledge::KnowledgeRecord(--double_array_->at (index));
1016  }
1017  else if (type_ == INTEGER_ARRAY)
1018  {
1019  unshare();
1020 
1021  if (int_array_->size () <= index) {
1022  int_array_->resize (index + 1);
1023  }
1024  return knowledge::KnowledgeRecord(--int_array_->at (index));
1025  }
1026  std::vector<Integer> tmp(index + 1);
1027  emplace_integers (std::move(tmp));
1028  return knowledge::KnowledgeRecord(--int_array_->at (index));
1029 }
1030 
1033 {
1034  if (type_ == DOUBLE_ARRAY)
1035  {
1036  unshare();
1037 
1038  if (double_array_->size () <= index) {
1039  double_array_->resize (index + 1);
1040  }
1041  return knowledge::KnowledgeRecord(++double_array_->at (index));
1042  }
1043  else if (type_ == INTEGER_ARRAY)
1044  {
1045  unshare();
1046 
1047  if (int_array_->size () <= index) {
1048  int_array_->resize (index + 1);
1049  }
1050  return knowledge::KnowledgeRecord(++int_array_->at (index));
1051  }
1052  std::vector<Integer> tmp(index + 1);
1053  emplace_integers (std::move(tmp));
1054  return knowledge::KnowledgeRecord(++int_array_->at (index));
1055 }
1056 
1057 void
1058 KnowledgeRecord::resize (size_t new_size)
1059 {
1060  size_t cur_size = size ();
1061 
1062  if (cur_size == new_size) {
1063  return;
1064  }
1065 
1066  unshare();
1067 
1068  if (new_size > cur_size)
1069  {
1070  if (type_ == EMPTY ||
1071  type_ == INTEGER)
1072  {
1073  Integer zero (0);
1074  set_index (new_size - 1, zero);
1075  return;
1076  }
1077  else if (type_ == DOUBLE)
1078  {
1079  double zero (0.0);
1080  set_index (new_size - 1, zero);
1081  return;
1082  }
1083  }
1084  if (type_ == INTEGER_ARRAY) {
1085  int_array_->resize (new_size);
1086  } else if (type_ == DOUBLE_ARRAY) {
1087  double_array_->resize (new_size);
1088  } else if (is_string_type (type_)) {
1089  str_value_->resize (new_size);
1090  } else if (is_binary_file_type (type_)) {
1091  file_value_->resize (new_size);
1092  }
1093 }
1094 
1095 int
1097  ThreadSafeContext & context,
1098  const std::string & key, unsigned int /*quality*/, uint64_t /*clock*/,
1099  bool perform_lock)
1100 {
1101  int result = -1;
1102 
1103  if (key.length () > 0)
1104  {
1105  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1106  " attempting to set %s=%s\n", key.c_str (), to_string ().c_str ());
1107 
1108  if (perform_lock)
1109  context.lock ();
1110 
1111  // if the data we are updating had a lower clock value or less quality
1112  // then that means this update is the latest value. Among
1113  // other things, this means our solution will work even
1114  // without FIFO channel transports
1115 
1116  // if the data we are updating had a lower clock value
1117  // then that means this update is the latest value. Among
1118  // other things, this means our solution will work even
1119  // without FIFO channel transports
1120  result = context.update_record_from_external (key, *this,
1122 
1123  if (perform_lock)
1124  {
1125  context.unlock ();
1126  context.set_changed ();
1127  }
1128 
1129  // if we actually updated the value
1130  if (result == 1)
1131  {
1132  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1133  " received data[%s]=%s.\n",
1134  key.c_str (), to_string ().c_str ());
1135  }
1136  // if the data was already current
1137  else if (result == 0)
1138  {
1139  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1140  " discarded data[%s]=%s as the value was already set.\n",
1141  key.c_str (), to_string ().c_str ());
1142  }
1143  else if (result == -1)
1144  {
1145  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1146  " discarded data due to null key.\n");
1147  }
1148  else if (result == -2)
1149  {
1150  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1151  " discarded data[%s]=%s due to lower quality.\n",
1152  key.c_str (), to_string ().c_str ());
1153  }
1154  else if (result == -3)
1155  {
1156  madara_logger_ptr_log (logger_, logger::LOG_MINOR, "KnowledgeRecord::apply:" \
1157  " discarded data[%s]=%" PRId64 " due to older timestamp.\n",
1158  key.c_str (), to_string ().c_str ());
1159  }
1160  }
1161  return result;
1162 }
1163 
1164 bool
1166 {
1167  madara_logger_ptr_log (logger_, logger::LOG_MAJOR, "KnowledgeRecord::apply:" \
1168  " checking if record is non-zero.\n");
1169 
1170  if (is_integer_type ())
1171  return to_integer () != 0;
1172  else if (is_double_type ())
1173  {
1174  double value = to_double ();
1175  return value < 0 || value > 0;
1176  }
1177  else if (is_string_type ())
1178  {
1179  return str_value_->size () > 1;
1180  }
1181  else if (is_binary_file_type ())
1182  {
1183  return file_value_->size () >= 1;
1184  }
1185  else
1186  {
1187  return false;
1188  }
1189 }
1190 
1191 } }
1192 
1193 #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.
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
MADARA_Export int read_file(const std::string &filename, void *&buffer, size_t &size, bool add_zero_char=false)
Reads a file into a provided void pointer.
Definition: Utility.cpp:747
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_
MADARA_Export std::string & lower(std::string &input)
Converts the string to lower.
Definition: Utility.cpp:127
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.
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 constexpr struct madara::knowledge::tags::doubles_t doubles
MADARA_Export ssize_t write_file(const std::string &filename, void *buffer, size_t size)
Writes a file with provided contents.
Definition: Utility.cpp:779
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 constexpr struct madara::knowledge::tags::string_t string
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
static constexpr struct madara::knowledge::tags::integers_t 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
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.