MADARA  3.4.1
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>
13 #include <cstring>
15 
16 namespace
17 {
18 int madara_double_precision(-1);
19 
20 bool madara_use_scientific(false);
21 } // namespace
22 
23 namespace madara
24 {
25 namespace knowledge
26 {
28 {
29  return madara_double_precision;
30 }
31 
32 void KnowledgeRecord::set_precision(int new_precision)
33 {
35  "KnowledgeRecord::set_precision:"
36  " setting precision to %d\n",
37  madara_double_precision);
38 
39  madara_double_precision = new_precision;
40 }
41 
43 {
45  "KnowledgeRecord::set_fixed:"
46  " setting output format to std::fixed\n");
47 
48  madara_use_scientific = false;
49 }
50 
52 {
54  "KnowledgeRecord::set_scientific:"
55  " setting output format to std::scientific\n");
56 
57  madara_use_scientific = true;
58 }
59 
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  if (has_history())
68  {
69  KnowledgeRecord tmp;
70  int ret = tmp.read_file(filename, read_as_type);
71  set_value(std::move(tmp));
72  return ret;
73  }
74 
75  // clear the old value
76  clear_value();
77 
78  std::string::size_type position = filename.rfind('.');
79  std::string extension = filename.substr(position, filename.size() - position);
80  madara::utility::lower(extension);
81 
82  // do we have a text-based file
83  if (is_string_type(read_as_type) || extension == ".txt" ||
84  extension == ".xml")
85  {
86  add_zero_char = false;
87  }
88 
89  // read the file into the temporary buffer
90  if (madara::utility::read_file(filename, buffer, size, add_zero_char) == 0)
91  {
92  // do we have a text-based file
93  if (is_string_type(read_as_type) || extension == ".txt" ||
94  extension == ".xml")
95  {
96  // change the string value and size to appropriate values
97  emplace_string((char*)buffer, size);
98 
99  if (is_string_type(read_as_type))
100  type_ = read_as_type;
101  else if (extension == ".xml")
102  type_ = XML;
103  else
104  type_ = TEXT_FILE;
105  }
106  else
107  {
108  unsigned char* ucbuf = (unsigned char*)buffer;
109  emplace_file(ucbuf, ucbuf + size);
110 
111  if (extension == ".jpg" || read_as_type == IMAGE_JPEG)
112  type_ = IMAGE_JPEG;
113  else
115  }
116 
117  return 0;
118  }
119  else
120  return -1;
121 }
122 
126 ssize_t KnowledgeRecord::to_file(const std::string& filename) const
127 {
128  if (is_string_type(type_))
129  {
131  filename, (void*)str_value_->c_str(), str_value_->size());
132  }
133  else if (is_binary_file_type(type_))
134  {
136  filename, (void*)&file_value_->at(0), file_value_->size());
137  }
138  else if (has_history())
139  {
140  if (buf_->empty())
141  {
142  buf_->emplace_back();
143  }
144  return ref_newest().to_file(filename);
145  }
146  else
147  {
148  std::string buffer(to_string());
149 
151  filename, (void*)buffer.c_str(), buffer.size());
152  }
153 }
154 
155 double KnowledgeRecord::to_double(void) const
156 {
157  double value = 0;
158 
159  if (!exists())
160  {
161  return value;
162  }
163 
164  if (type_ == DOUBLE)
165  value = double_value_;
166  else if (type_ == DOUBLE_ARRAY)
167  value = double_array_->size() == 0 ? 0 : double_array_->at(0);
168  else if (has_history())
169  value = ref_newest().to_double();
170  else
171  {
172  std::stringstream buffer;
173 
174  // read the value_ into a stringstream and then convert it to double
175  if (type_ == INTEGER)
176  buffer << int_value_;
177  else if (type_ == INTEGER_ARRAY)
178  buffer << (int_array_->size() == 0 ? 0 : int_array_->at(0));
179  else if (is_string_type(type_))
180  buffer << str_value_->c_str();
181 
182  buffer >> value;
183  }
184 
185  return value;
186 }
187 
189 {
190  Integer value(0);
191 
192  if (!exists())
193  {
194  return value;
195  }
196 
197  if (type_ == INTEGER)
198  value = int_value_;
199  else if (type_ == INTEGER_ARRAY)
200  value = int_array_->size() == 0 ? 0 : int_array_->at(0);
201  else if (has_history())
202  value = ref_newest().to_integer();
203  else
204  {
205  std::stringstream buffer;
206 
207  // read the value_ into a stringstream and then convert it to double
208  if (type_ == DOUBLE)
209  buffer << double_value_;
210  else if (type_ == DOUBLE_ARRAY)
211  buffer << (double_array_->size() == 0 ? 0 : double_array_->at(0));
212  else if (is_string_type(type_))
213  buffer << str_value_->c_str();
214 
215  buffer >> value;
216  }
217 
218  return value;
219 }
220 
221 std::vector<KnowledgeRecord::Integer> KnowledgeRecord::to_integers(void) const
222 {
223  std::vector<Integer> integers;
224 
225  if (!exists())
226  {
227  return integers;
228  }
229 
230  if (has_history())
231  {
232  return ref_newest().to_integers();
233  }
234 
235  unsigned int size = (unsigned int)this->size();
236  integers.resize(size);
237 
238  if (type_ == INTEGER)
239  {
240  integers[0] = int_value_;
241  }
242  else if (type_ == INTEGER_ARRAY)
243  {
244  const Integer* ptr_temp = &(*int_array_)[0];
245 
246  for (unsigned int i = 0; i < size; ++i)
247  integers[i] = ptr_temp[i];
248  }
249  else if (type_ == DOUBLE)
251  else if (type_ == DOUBLE_ARRAY)
252  {
253  const double* ptr_temp = &(*double_array_)[0];
254 
255  for (unsigned int i = 0; i < size; ++i)
256  integers[i] = Integer(ptr_temp[i]);
257  }
258  else if (is_string_type(type_))
259  {
260  const char* ptr_temp = str_value_->c_str();
261 
262  for (unsigned int i = 0; i < size; ++i)
263  integers[i] = Integer(ptr_temp[i]);
264  }
265  else if (is_binary_file_type(type_))
266  {
267  const unsigned char* ptr_temp = &(*file_value_)[0];
268 
269  for (unsigned int i = 0; i < size; ++i)
270  integers[i] = Integer(ptr_temp[i]);
271  }
272 
273  return integers;
274 }
275 
276 std::vector<double> KnowledgeRecord::to_doubles(void) const
277 {
278  std::vector<double> doubles;
279 
280  if (!exists())
281  {
282  return doubles;
283  }
284 
285  if (has_history())
286  {
287  return ref_newest().to_doubles();
288  }
289 
290  unsigned int size = (unsigned int)this->size();
291  doubles.resize(size);
292 
293  if (type_ == INTEGER)
294  doubles[0] = double(int_value_);
295  else if (type_ == INTEGER_ARRAY)
296  {
297  const Integer* ptr_temp = &(*int_array_)[0];
298 
299  for (unsigned int i = 0; i < size; ++i)
300  doubles[i] = double(ptr_temp[i]);
301  }
302  else if (type_ == DOUBLE)
303  doubles[0] = double_value_;
304  else if (type_ == DOUBLE_ARRAY)
305  {
306  const double* ptr_temp = &(*double_array_)[0];
307 
308  for (unsigned int i = 0; i < size; ++i)
309  doubles[i] = ptr_temp[i];
310  }
311  else if (is_string_type(type_))
312  {
313  const char* ptr_temp = str_value_->c_str();
314 
315  for (unsigned int i = 0; i < size; ++i)
316  doubles[i] = double(ptr_temp[i]);
317  }
318  else if (is_binary_file_type(type_))
319  {
320  const unsigned char* ptr_temp = &(*file_value_)[0];
321 
322  for (unsigned int i = 0; i < size; ++i)
323  doubles[i] = double(ptr_temp[i]);
324  }
325 
326  return doubles;
327 }
328 
329 size_t KnowledgeRecord::to_managed_string(char* buffer, size_t buf_size) const
330 {
331  std::string contents = to_string();
332  size_t len = std::min(buf_size, contents.length() + 1);
333  utility::strncpy_safe(buffer, contents.c_str(), len);
334 
335  return len;
336 }
337 
338 size_t KnowledgeRecord::to_managed_buffer(char* buffer, size_t buf_size) const
339 {
340  size_t actual_size = 0;
341 
342  if (is_string_type(type_))
343  {
344  actual_size = std::min(str_value_->size(), buf_size);
345  memcpy(buffer, str_value_->c_str(), actual_size);
346  }
347  else if (is_binary_file_type(type_))
348  {
349  actual_size = std::min(file_value_->size(), buf_size);
350  memcpy(buffer, &(*file_value_)[0], actual_size);
351  }
352  else if (type_ == INTEGER)
353  {
354  if (sizeof(Integer) <= buf_size)
355  {
356  actual_size = std::min(sizeof(Integer), buf_size);
357  memcpy(buffer, &int_value_, actual_size);
358  }
359  }
360  else if (type_ == DOUBLE)
361  {
362  if (sizeof(Integer) <= buf_size)
363  {
364  actual_size = std::min(sizeof(double), buf_size);
365  memcpy(buffer, &double_value_, actual_size);
366  }
367  }
368  else if (type_ == INTEGER_ARRAY)
369  {
370  if (sizeof(Integer) * int_array_->size() <= buf_size)
371  {
372  actual_size = std::min(sizeof(Integer) * int_array_->size(), buf_size);
373  memcpy(buffer, &(*int_array_)[0], actual_size);
374  }
375  }
376  else if (type_ == DOUBLE_ARRAY)
377  {
378  if (sizeof(double) * int_array_->size() <= buf_size)
379  {
380  actual_size = std::min(sizeof(double) * int_array_->size(), buf_size);
381  memcpy(buffer, &(*double_array_)[0], actual_size);
382  }
383  }
384  else if (has_history() && !buf_->empty())
385  {
386  actual_size = ref_newest().to_managed_buffer(buffer, buf_size);
387  }
388  else
389  {
390  if (buf_size > 0)
391  {
392  buffer[0] = 0;
393  }
394  actual_size = 0;
395  }
396 
397  return actual_size;
398 }
399 
400 // read the value_ in a string format
402 {
403  if (!exists())
404  {
405  return "";
406  }
407 
408  if (has_history())
409  {
410  return ref_newest().to_string();
411  }
412 
413  if (!is_string_type(type_))
414  {
416  "KnowledgeRecord::to_string:"
417  " type_ is %d\n",
418  type_);
419 
420  std::stringstream buffer;
421 
422  if (type_ == INTEGER)
423  buffer << int_value_;
424  else if (type_ == INTEGER_ARRAY)
425  {
426  const Integer* ptr_temp = &(*int_array_)[0];
427  uint32_t size = this->size();
428 
429  if (size >= 1)
430  buffer << *ptr_temp;
431 
432  ++ptr_temp;
433 
434  for (uint32_t i = 1; i < size; ++i, ++ptr_temp)
435  buffer << delimiter << *ptr_temp;
436  }
437  else if (type_ == DOUBLE)
438  {
439  // set fixed or scientific
440  if (!madara_use_scientific)
441  {
443  "KnowledgeRecord::to_string: using fixed format\n");
444 
445  buffer << std::fixed;
446  }
447  else
448  {
450  "KnowledgeRecord::to_string: using scientific format\n");
451 
452  buffer << std::scientific;
453  }
454 
455  if (madara_double_precision >= 0)
456  {
457  // set the precision of double output
458  buffer << std::setprecision(madara_double_precision);
459 
461  "KnowledgeRecord::to_string:"
462  " precision set to %d\n",
463  madara_double_precision);
464  }
465  else
466  {
468  "KnowledgeRecord::to_string:"
469  " precision set to default\n",
470  madara_double_precision);
471  }
472 
473  buffer << double_value_;
474  }
475  else if (type_ == DOUBLE_ARRAY)
476  {
477  // set fixed or scientific
478  if (!madara_use_scientific)
479  {
481  "KnowledgeRecord::to_string: using fixed format\n");
482 
483  buffer << std::fixed;
484  }
485  else
486  {
488  "KnowledgeRecord::to_string: using scientific format\n");
489 
490  buffer << std::scientific;
491  }
492 
493  if (madara_double_precision >= 0)
494  {
495  buffer << std::setprecision(madara_double_precision);
496 
498  "KnowledgeRecord::to_string:"
499  " precision set to %d\n",
500  madara_double_precision);
501  }
502  else
503  {
505  "KnowledgeRecord::to_string:"
506  " precision set to default\n",
507  madara_double_precision);
508  }
509 
510  const double* ptr_temp = &(*double_array_)[0];
511  uint32_t size = this->size();
512 
513  if (size >= 1)
514  buffer << *ptr_temp;
515 
516  ++ptr_temp;
517 
518  for (uint32_t i = 1; i < size; ++i, ++ptr_temp)
519  buffer << delimiter << *ptr_temp;
520  }
521  else if (is_binary_file_type(type_))
522  {
523  buffer << "binary:size=";
524  buffer << size();
525  }
526  return buffer.str();
527  }
528  else
529  return std::string(*str_value_);
530 }
531 
532 // read the value_ in a string format
533 unsigned char* KnowledgeRecord::to_unmanaged_buffer(size_t& size) const
534 {
535  char* buffer;
536 
537  if (is_string_type(type_))
538  {
539  size = str_value_->size();
540  buffer = new char[size];
541  memcpy(buffer, str_value_->c_str(), size);
542  }
543  else if (is_binary_file_type(type_))
544  {
545  size = file_value_->size();
546  buffer = new char[size];
547  memcpy(buffer, &(*file_value_)[0], size);
548  }
549  else if (type_ == INTEGER)
550  {
551  size = sizeof(Integer);
552  buffer = new char[size];
553  memcpy(buffer, &int_value_, size);
554  }
555  else if (type_ == DOUBLE)
556  {
557  size = sizeof(double);
558  buffer = new char[size];
559  memcpy(buffer, &double_value_, size);
560  }
561  else if (type_ == INTEGER_ARRAY)
562  {
563  size = sizeof(Integer) * int_array_->size();
564  buffer = new char[size];
565  memcpy(buffer, &(*int_array_)[0], size);
566  }
567  else if (type_ == DOUBLE_ARRAY)
568  {
569  size = sizeof(double) * double_array_->size();
570  buffer = new char[size];
571  memcpy(buffer, &(*double_array_)[0], size);
572  }
573  else if (has_history() && !buf_->empty())
574  {
576  }
577  else
578  {
579  buffer = nullptr;
580  size = 0;
581  }
582 
583  return (unsigned char*)buffer;
584 }
585 
586 KnowledgeRecord KnowledgeRecord::fragment(unsigned int first, unsigned int last)
587 {
589 
590  if (!exists())
591  {
592  return ret;
593  }
594 
595  if (has_history())
596  {
597  return fragment(first, last);
598  }
599 
600  if (is_string_type(type_))
601  {
602  unsigned int size = (unsigned int)str_value_->size();
603 
604  // make sure last is accessible in the data type
605  last = std::min<unsigned int>(last, size - 1);
606 
607  // Create a new buffer, copy over the elements, and add a null delimiter
608  char* new_buffer = new char[last - first + 2];
609 
610  memcpy(new_buffer, str_value_->c_str() + first, last - first + 1);
611  new_buffer[last - first + 1] = 0;
612 
613  ret.set_value(new_buffer);
614  }
615  else if (is_binary_file_type(type_))
616  {
617  unsigned int size = (unsigned int)file_value_->size();
618 
619  // make sure last is accessible in the data type
620  last = std::min<unsigned int>(last, (unsigned int)size - 1);
621 
622  // Unlike string types, file buffers are not ended with a null delimiter
623  uint32_t bufsize = last - first + 1;
624  unsigned char* new_buffer = new unsigned char[bufsize];
625 
626  memcpy(new_buffer, &(*file_value_)[0] + first, last - first + 1);
627 
628  // create a new record with the unsigned char buffer as contents
629  ret.set_file(new_buffer, bufsize);
630  }
631  else if (type_ == INTEGER_ARRAY)
632  {
633  unsigned int size = (unsigned int)int_array_->size();
634 
635  // make sure last is accessible in the data type
636  last = std::min<unsigned int>(last, size - 1);
637  uint32_t bufsize = last - first + 1;
638 
639  std::vector<Integer> integers;
640  integers.resize(bufsize);
641  Integer* ptr_temp = &(*int_array_)[0];
642 
643  for (unsigned int i = first; i <= last; ++i, ++ptr_temp)
644  integers[i] = *ptr_temp;
645 
646  ret.set_value(integers);
647  }
648  else if (type_ == DOUBLE_ARRAY)
649  {
650  unsigned int size = (unsigned int)double_array_->size();
651 
652  // make sure last is accessible in the data type
653  last = std::min<unsigned int>(last, size - 1);
654  uint32_t bufsize = last - first + 1;
655 
656  std::vector<double> doubles;
657  doubles.resize(bufsize);
658  double* ptr_temp = &(*double_array_)[0];
659 
660  for (unsigned int i = first; i <= last; ++i, ++ptr_temp)
661  doubles[i] = *ptr_temp;
662 
663  ret.set_value(doubles);
664  }
665 
666  return ret;
667 }
668 
670 {
671  if (has_history())
672  {
673  return (rhs.buf_->empty() ? KnowledgeRecord{} : ref_newest())
674  .
675  operator<(rhs);
676  }
677 
678  if (rhs.has_history())
679  {
680  return operator<(rhs.buf_->empty() ? KnowledgeRecord{} : rhs.ref_newest());
681  }
682 
683  Integer result(0);
684 
685  // if the left hand side is an integer
686  if (is_integer_type(type_))
687  {
688  Integer lhs = this->to_integer();
689 
690  if (is_double_type(rhs.type_) || is_string_type(rhs.type_))
691  {
692  double other = rhs.to_double();
693 
694  result = lhs < other;
695  }
696  else if (is_integer_type(rhs.type_))
697  {
698  Integer other = rhs.to_integer();
699 
700  result = lhs < other;
701  }
702  }
703 
704  // if the left hand side is a string
705  else if (is_string_type(type_))
706  {
707  // string to string comparison
708  if (is_string_type(rhs.type_))
709  {
710  result = strncmp(str_value_->c_str(), rhs.str_value_->c_str(),
711  size() >= rhs.size() ? size() : rhs.size()) < 0;
712  }
713 
714  // string to double comparison
715  else if (is_double_type(rhs.type_))
716  {
717  // when comparing strings to anything else, convert the
718  // value into a double for maximum precision
719  double temp = to_double();
720  double other = rhs.to_double();
721 
722  result = temp < other;
723  }
724 
725  // default is string to integer comparison
726  else if (is_integer_type(rhs.type_))
727  {
728  // when comparing strings to anything else, convert the
729  // value into a double for maximum precision
730  Integer temp = to_integer();
731  Integer other = rhs.to_integer();
732 
733  result = temp < other;
734  }
735  }
736 
737  // if the left hand side is a double
738  else if (is_double_type(type_))
739  {
740  double lhs = to_double();
741 
742  // string to string comparison
743  if (is_string_type(rhs.type_) || is_double_type(rhs.type_))
744  {
745  // when comparing strings to anything else, convert the
746  // value into a double for maximum precision
747 
748  double other = rhs.to_double();
749 
750  result = lhs < other;
751  }
752 
753  // default is string to integer comparison
754  else if (is_integer_type(rhs.type_))
755  {
756  Integer other = rhs.to_integer();
757  result = lhs < other;
758  }
759  }
760 
761  return result != 0;
762 }
763 
765 {
766  if (has_history())
767  {
768  return (rhs.buf_->empty() ? KnowledgeRecord{} : ref_newest())
769  .
770  operator<=(rhs);
771  }
772 
773  if (rhs.has_history())
774  {
775  return operator<=(rhs.buf_->empty() ? KnowledgeRecord{} : rhs.ref_newest());
776  }
777 
778  Integer result(0);
779 
780  // if the left hand side is an integer
781  if (is_integer_type(type_))
782  {
783  Integer lhs = this->to_integer();
784 
785  if (is_double_type(rhs.type_) || is_string_type(rhs.type_))
786  {
787  double other = rhs.to_double();
788 
789  result = lhs <= other;
790  }
791  else if (is_integer_type(rhs.type_))
792  {
793  Integer other = rhs.to_integer();
794 
795  result = lhs <= other;
796  }
797  }
798 
799  // if the left hand side is a string
800  else if (is_string_type(type_))
801  {
802  // string to string comparison
803  if (is_string_type(rhs.type_))
804  {
805  result = strncmp(str_value_->c_str(), rhs.str_value_->c_str(),
806  size() >= rhs.size() ? size() : rhs.size()) <= 0;
807  }
808 
809  // string to double comparison
810  else if (is_double_type(rhs.type_))
811  {
812  // when comparing strings to anything else, convert the
813  // value into a double for maximum precision
814  double temp = to_double();
815  double other = rhs.to_double();
816 
817  result = temp <= other;
818  }
819 
820  // default is string to integer comparison
821  else if (is_integer_type(rhs.type_))
822  {
823  // when comparing strings to anything else, convert the
824  // value into a double for maximum precision
825  Integer temp = to_integer();
826  Integer other = rhs.to_integer();
827 
828  result = temp <= other;
829  }
830  }
831 
832  // if the left hand side is a double
833  else if (is_double_type(type_))
834  {
835  double lhs = to_double();
836 
837  // string to string comparison
838  if (is_string_type(rhs.type_) || is_double_type(rhs.type_))
839  {
840  // when comparing strings to anything else, convert the
841  // value into a double for maximum precision
842 
843  double other = rhs.to_double();
844 
845  result = lhs <= other;
846  }
847 
848  // default is string to integer comparison
849  else if (is_integer_type(rhs.type_))
850  {
851  Integer other = rhs.to_integer();
852  result = lhs <= other;
853  }
854  }
855 
856  return result != 0;
857 }
858 
860 {
861  if (has_history())
862  {
863  return (rhs.buf_->empty() ? KnowledgeRecord{} : ref_newest())
864  .
865  operator==(rhs);
866  }
867 
868  if (rhs.has_history())
869  {
870  return operator==(rhs.buf_->empty() ? KnowledgeRecord{} : rhs.ref_newest());
871  }
872 
873  Integer result(0);
874 
875  // if left hand side does
876  if (!exists())
877  {
878  if (!rhs.exists() || rhs.is_false())
879  {
880  result = 1;
881  }
882  }
883 
884  // if the left hand side is an integer
885  else if (is_integer_type(type_))
886  {
887  if (is_double_type(rhs.type_))
888  {
889  result = to_double() == rhs.to_double();
890  }
891  else if (is_integer_type(rhs.type_))
892  {
893  result = to_integer() == rhs.to_integer();
894  }
895  else if (is_string_type(rhs.type_))
896  {
897  if (rhs.size() > 0 && rhs.str_value_->at(0) >= '0' &&
898  rhs.str_value_->at(0) <= '9')
899  {
900  result = to_double() == rhs.to_double();
901  }
902  else
903  result = 0;
904  }
905  }
906 
907  // if the left hand side is a string
908  else if (is_string_type(type_))
909  {
910  // string to string comparison
911  if (is_string_type(rhs.type_))
912  {
913  result = strncmp(str_value_->c_str(), rhs.str_value_->c_str(),
914  size() >= rhs.size() ? size() : rhs.size()) == 0;
915  }
916 
917  // string to double comparison
918  else if (is_double_type(rhs.type_))
919  {
920  // when comparing strings to anything else, convert the
921  // value into a double for maximum precision
922  result = to_double() == rhs.to_double();
923  }
924 
925  // check if right hand side is uncreated
926  else if (!rhs.exists())
927  {
928  result = is_false();
929  }
930 
931  // default is string to integer comparison
932  else if (is_integer_type(rhs.type_))
933  {
934  if (size() > 0 && this->str_value_->at(0) >= '0' &&
935  this->str_value_->at(0) <= '9')
936  {
937  result = to_double() == rhs.to_double();
938  }
939  else
940  {
941  result = 0;
942  }
943  }
944  }
945 
946  // if the left hand side is a double
947  else if (is_double_type(type_))
948  {
949  double lhs = to_double();
950 
951  // string to string comparison
952  if (is_string_type(rhs.type_) || is_double_type(rhs.type_))
953  {
954  // when comparing strings to anything else, convert the
955  // value into a double for maximum precision
956 
957  double other = rhs.to_double();
958 
959  result = lhs == other;
960  }
961 
962  // default is string to integer comparison
963  else if (is_integer_type(rhs.type_))
964  {
965  Integer other = rhs.to_integer();
966 
967  result = lhs == other;
968  }
969  }
970 
971  return result != 0;
972 }
973 
975 {
976  if (has_history())
977  {
978  return (rhs.buf_->empty() ? KnowledgeRecord{} : ref_newest())
979  .
980  operator>(rhs);
981  }
982 
983  if (rhs.has_history())
984  {
985  return operator>(rhs.buf_->empty() ? KnowledgeRecord{} : rhs.ref_newest());
986  }
987 
988  Integer result(0);
989 
990  // if the left hand side is an integer
991  if (is_integer_type(type_))
992  {
993  Integer lhs = this->to_integer();
994 
995  if (is_double_type(rhs.type_) || is_string_type(rhs.type_))
996  {
997  double other = rhs.to_double();
998 
999  result = lhs > other;
1000  }
1001  else if (is_integer_type(rhs.type_))
1002  {
1003  Integer other = rhs.to_integer();
1004 
1005  result = lhs > other;
1006  }
1007  }
1008 
1009  // if the left hand side is a string
1010  else if (is_string_type(type_))
1011  {
1012  // string to string comparison
1013  if (is_string_type(rhs.type_))
1014  {
1015  result = strncmp(str_value_->c_str(), rhs.str_value_->c_str(),
1016  size() >= rhs.size() ? size() : rhs.size()) > 0;
1017  }
1018 
1019  // string to double comparison
1020  else if (is_double_type(rhs.type_))
1021  {
1022  // when comparing strings to anything else, convert the
1023  // value into a double for maximum precision
1024  double lhs = to_double();
1025  double other = rhs.to_double();
1026 
1027  result = lhs > other;
1028  }
1029 
1030  // default is string to integer comparison
1031  else if (is_integer_type(rhs.type_))
1032  {
1033  // when comparing strings to anything else, convert the
1034  // value into a double for maximum precision
1035  Integer lhs = to_integer();
1036  Integer other = rhs.to_integer();
1037 
1038  result = lhs > other;
1039  }
1040  }
1041 
1042  // if the left hand side is a double
1043  else if (is_double_type(type_))
1044  {
1045  double lhs = to_double();
1046 
1047  // string to string comparison
1048  if (is_string_type(rhs.type_) || is_double_type(rhs.type_))
1049  {
1050  // when comparing strings to anything else, convert the
1051  // value into a double for maximum precision
1052 
1053  double other = rhs.to_double();
1054 
1055  result = lhs > other;
1056  }
1057 
1058  // default is string to integer comparison
1059  else if (is_integer_type(rhs.type_))
1060  {
1061  Integer other = rhs.to_integer();
1062 
1063  result = lhs > other;
1064  }
1065  }
1066 
1067  return result != 0;
1068 }
1069 
1071 {
1072  if (has_history())
1073  {
1074  return (rhs.buf_->empty() ? KnowledgeRecord{} : ref_newest())
1075  .
1076  operator>=(rhs);
1077  }
1078 
1079  if (rhs.has_history())
1080  {
1081  return operator>=(rhs.buf_->empty() ? KnowledgeRecord{} : rhs.ref_newest());
1082  }
1083 
1084  Integer result(0);
1085 
1086  // if the left hand side is an integer
1087  if (is_integer_type(type_))
1088  {
1089  Integer lhs = this->to_integer();
1090 
1091  if (is_double_type(rhs.type_) || is_string_type(rhs.type_))
1092  {
1093  double other = rhs.to_double();
1094 
1095  result = lhs >= other;
1096  }
1097  else if (is_integer_type(rhs.type_))
1098  {
1099  Integer other = rhs.to_integer();
1100 
1101  result = lhs >= other;
1102  }
1103  }
1104 
1105  // if the left hand side is a string
1106  else if (is_string_type(type_))
1107  {
1108  // string to string comparison
1109  if (is_string_type(rhs.type_))
1110  {
1111  result = strncmp(str_value_->c_str(), rhs.str_value_->c_str(),
1112  size() >= rhs.size() ? size() : rhs.size()) >= 0;
1113  }
1114 
1115  // string to double comparison
1116  else if (is_double_type(rhs.type_))
1117  {
1118  // when comparing strings to anything else, convert the
1119  // value into a double for maximum precision
1120  double lhs = to_double();
1121  double other = rhs.to_double();
1122 
1123  result = lhs >= other;
1124  }
1125 
1126  // default is string to integer comparison
1127  else if (is_integer_type(rhs.type_))
1128  {
1129  // when comparing strings to anything else, convert the
1130  // value into a double for maximum precision
1131  Integer lhs = to_integer();
1132  Integer other = rhs.to_integer();
1133 
1134  result = lhs >= other;
1135  }
1136  }
1137 
1138  // if the left hand side is a double
1139  else if (is_double_type(type_))
1140  {
1141  double lhs = to_double();
1142 
1143  // string to string comparison
1144  if (is_string_type(rhs.type_) || is_double_type(rhs.type_))
1145  {
1146  // when comparing strings to anything else, convert the
1147  // value into a double for maximum precision
1148 
1149  double other = rhs.to_double();
1150 
1151  result = lhs >= other;
1152  }
1153 
1154  // default is string to integer comparison
1155  else if (is_integer_type(rhs.type_))
1156  {
1157  Integer other = rhs.to_integer();
1158 
1159  result = lhs >= other;
1160  }
1161  }
1162 
1163  return result != 0;
1164 }
1165 
1167 {
1168  knowledge::KnowledgeRecord ret_value;
1169 
1170  if (type_ == INTEGER_ARRAY)
1171  {
1172  if (index < size_t(int_array_->size()))
1173  ret_value.set_value(int_array_->at(index));
1174  }
1175  else if (type_ == DOUBLE_ARRAY)
1176  {
1177  if (index < size_t(double_array_->size()))
1178  ret_value.set_value(double_array_->at(index));
1179  }
1180  else if (has_history() && !buf_->empty())
1181  {
1182  return ref_newest().retrieve_index(index);
1183  }
1184 
1185  return ret_value;
1186 }
1187 
1189 {
1190  if (type_ == DOUBLE_ARRAY)
1191  {
1192  unshare();
1193 
1194  if (double_array_->size() <= index)
1195  {
1196  double_array_->resize(index + 1);
1197  }
1198  return knowledge::KnowledgeRecord(--double_array_->at(index));
1199  }
1200  else if (type_ == INTEGER_ARRAY)
1201  {
1202  unshare();
1203 
1204  if (int_array_->size() <= index)
1205  {
1206  int_array_->resize(index + 1);
1207  }
1208  return knowledge::KnowledgeRecord(--int_array_->at(index));
1209  }
1210  else if (has_history())
1211  {
1212  KnowledgeRecord tmp = get_newest();
1213  tmp.dec_index(index);
1214  set_value(tmp);
1215  return tmp;
1216  }
1217  std::vector<Integer> tmp(index + 1);
1218  emplace_integers(std::move(tmp));
1219  return knowledge::KnowledgeRecord(--int_array_->at(index));
1220 }
1221 
1223 {
1224  if (type_ == DOUBLE_ARRAY)
1225  {
1226  unshare();
1227 
1228  if (double_array_->size() <= index)
1229  {
1230  double_array_->resize(index + 1);
1231  }
1232  return knowledge::KnowledgeRecord(++double_array_->at(index));
1233  }
1234  else if (type_ == INTEGER_ARRAY)
1235  {
1236  unshare();
1237 
1238  if (int_array_->size() <= index)
1239  {
1240  int_array_->resize(index + 1);
1241  }
1242  return knowledge::KnowledgeRecord(++int_array_->at(index));
1243  }
1244  else if (has_history())
1245  {
1246  KnowledgeRecord tmp = get_newest();
1247  tmp.inc_index(index);
1248  set_value(tmp);
1249  return tmp;
1250  }
1251  std::vector<Integer> tmp(index + 1);
1252  emplace_integers(std::move(tmp));
1253  return knowledge::KnowledgeRecord(++int_array_->at(index));
1254 }
1255 
1256 void KnowledgeRecord::resize(size_t new_size)
1257 {
1258  if (has_history())
1259  {
1260  KnowledgeRecord tmp = get_newest();
1261  tmp.resize(new_size);
1262  set_value(std::move(tmp));
1263  return;
1264  }
1265 
1266  size_t cur_size = size();
1267 
1268  if (cur_size == new_size)
1269  {
1270  return;
1271  }
1272 
1273  unshare();
1274 
1275  if (new_size > cur_size)
1276  {
1277  if (!exists() || type_ == INTEGER)
1278  {
1279  Integer zero(0);
1280  set_index(new_size - 1, zero);
1281  return;
1282  }
1283  else if (type_ == DOUBLE)
1284  {
1285  double zero(0.0);
1286  set_index(new_size - 1, zero);
1287  return;
1288  }
1289  }
1290  if (type_ == INTEGER_ARRAY)
1291  {
1292  int_array_->resize(new_size);
1293  }
1294  else if (type_ == DOUBLE_ARRAY)
1295  {
1296  double_array_->resize(new_size);
1297  }
1298  else if (is_string_type(type_))
1299  {
1300  str_value_->resize(new_size);
1301  }
1302  else if (is_binary_file_type(type_))
1303  {
1304  file_value_->resize(new_size);
1305  }
1306 }
1307 
1309  unsigned int /*quality*/, uint64_t /*clock*/, bool perform_lock)
1310 {
1311  int result = -1;
1312 
1313  if (key.length() > 0)
1314  {
1316  "KnowledgeRecord::apply:"
1317  " attempting to set %s=%s\n",
1318  key.c_str(), to_string().c_str());
1319 
1320  if (perform_lock)
1321  context.lock();
1322 
1323  // if the data we are updating had a lower clock value or less quality
1324  // then that means this update is the latest value. Among
1325  // other things, this means our solution will work even
1326  // without FIFO channel transports
1327 
1328  // if the data we are updating had a lower clock value
1329  // then that means this update is the latest value. Among
1330  // other things, this means our solution will work even
1331  // without FIFO channel transports
1332  result = context.update_record_from_external(key, *this,
1334 
1335  if (perform_lock)
1336  {
1337  context.unlock();
1338  context.set_changed();
1339  }
1340 
1341  // if we actually updated the value
1342  if (result == 1)
1343  {
1345  "KnowledgeRecord::apply:"
1346  " received data[%s]=%s.\n",
1347  key.c_str(), to_string().c_str());
1348  }
1349  // if the data was already current
1350  else if (result == 0)
1351  {
1353  "KnowledgeRecord::apply:"
1354  " discarded data[%s]=%s as the value was already set.\n",
1355  key.c_str(), to_string().c_str());
1356  }
1357  else if (result == -1)
1358  {
1360  "KnowledgeRecord::apply:"
1361  " discarded data due to null key.\n");
1362  }
1363  else if (result == -2)
1364  {
1366  "KnowledgeRecord::apply:"
1367  " discarded data[%s]=%s due to lower quality.\n",
1368  key.c_str(), to_string().c_str());
1369  }
1370  else if (result == -3)
1371  {
1373  "KnowledgeRecord::apply:"
1374  " discarded data[%s]=%" PRId64 " due to older timestamp.\n",
1375  key.c_str(), to_string().c_str());
1376  }
1377  }
1378  return result;
1379 }
1380 
1382 {
1384  "KnowledgeRecord::apply:"
1385  " checking if record is non-zero.\n");
1386 
1387  if (is_integer_type(type_))
1388  return to_integer() != 0;
1389  else if (is_double_type(type_))
1390  {
1391  double value = to_double();
1392  return value < 0 || value > 0;
1393  }
1394  else if (is_string_type(type_))
1395  {
1396  return str_value_->size() >= 1;
1397  }
1398  else if (is_binary_file_type(type_))
1399  {
1400  return file_value_->size() >= 1;
1401  }
1402  else if (has_history())
1403  {
1404  return !buf_->empty() && ref_newest().is_true();
1405  }
1406  else
1407  {
1408  return false;
1409  }
1410 }
1411 
1413 {
1414  map.clear();
1415 }
1416 
1417 } // namespace knowledge
1418 } // namespace madara
1419 
1420 #endif // _KNOWLEDGE_RECORD_CPP_
#define madara_logger_ptr_log(loggering, level,...)
Fast version of the madara::logger::log method for Logger pointers.
Definition: Logger.h:41
madara::knowledge::KnowledgeRecord KnowledgeRecord
This class encapsulates an entry in a KnowledgeBase.
size_t to_managed_buffer(char *buffer, size_t buf_size) const
converts the value to a c string.
bool has_history() const
Return true if this record has a circular buffer history.
std::string to_string(const std::string &delimiter=", ") const
converts the value to a string.
std::shared_ptr< std::string > str_value_
void emplace_file(Args &&... args)
Construct a file (vector of unsigned char) within this KnowledgeRecord.
std::vector< Integer > to_integers(void) const
converts the value to a vector of integers
std::shared_ptr< std::vector< unsigned char > > file_value_
bool is_double_type(void) const
returns if the record is a double type (DOUBLE, DOUBLE_ARRAY)
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.
void set_value(const KnowledgeRecord &new_value)
Sets the value from another KnowledgeRecord, does not copy toi, clock, and write_quality.
double to_double(void) const
converts the value to a float/double.
bool operator<=(const KnowledgeRecord &rhs) const
Less than or equal to.
bool is_true(void) const
Checks to see if the record is true.
bool operator>=(const KnowledgeRecord &rhs) const
Greater than or equal to.
KnowledgeRecord fragment(unsigned int first, unsigned int last)
returns a record containing a fragment of the character buffer.
static void set_fixed(void)
Sets the output format for doubles to std::fixed.
KnowledgeRecord inc_index(size_t index)
increments the value at the index to the specified value.
KnowledgeRecord dec_index(size_t index)
decrements the value at the index to the specified value.
KnowledgeRecord retrieve_index(size_t index) const
retrieves the value at an array index.
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.
uint32_t size(void) const
returns the size of the value
std::shared_ptr< std::vector< Integer > > int_array_
bool exists(void) const
Checks if record exists (i.e., is not uncreated)
bool is_integer_type(void) const
returns if the record is a integer type (INTEGER, INTEGER_ARRAY)
bool is_binary_file_type(void) const
returns true if the knowledge record has a binary file type
static int get_precision(void)
Gets the current double precision for double to string conversion.
uint32_t type_
type of variable (INTEGER, DOUBLE, STRING, FILE, IMAGE)
Integer to_integer(void) const
converts the value to an integer.
bool is_string_type(void) const
returns true if the record is a string type (STRING, XML, TEXT_FILE)
bool operator<(const KnowledgeRecord &rhs) const
Less than.
size_t to_managed_string(char *buffer, size_t buf_size) const
converts the value to a c string.
bool operator==(const KnowledgeRecord &rhs) const
Equal to.
KnowledgeRecord get_newest() const
Return the newest stored history entry of this record.
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
void emplace_string(Args &&... args)
Construct a string within this KnowledgeRecord.
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...
ssize_t to_file(const std::string &filename) const
writes the value to a file
bool operator>(const KnowledgeRecord &rhs) const
Greater than.
void clear_value(void) noexcept
clears any dynamic values.
void emplace_integers(Args &&... args)
Construct a vector of integers within this KnowledgeRecord.
std::shared_ptr< CircBuf > buf_
logger::Logger * logger_
the logger used for any internal debugging information
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 ().
void set_file(const unsigned char *new_value, size_t size)
sets the value to an unknown file type
static void set_scientific(void)
Sets the output format for doubles to std::scientific.
bool is_false(void) const
Checks to see if the record is false.
void unshare(void)
If this record holds a shared_ptr, make a copy of the underlying value so it has an exclusive copy.
void resize(size_t new_size)
resizes an array to a new size
static const KnowledgeUpdateSettings GLOBAL_AS_LOCAL_NO_EXPAND
This class stores variables and their values for use by any entity needing state information in a thr...
void unlock(void) const
Unlocks the mutex on this context.
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.
void set_changed(void)
Force a change to be registered, waking up anyone waiting on entry.
void lock(void) const
Locks the mutex on this context.
constexpr doubles_t doubles
constexpr integers_t integers
constexpr string_t string
Provides functions and classes for the distributed knowledge base.
T get(const KnowledgeRecord &kr)
Get the value of a KnowlegeRecord.
Definition: GetRecord.h:121
void safe_clear(KnowledgeMap &map)
::std::map< std::string, KnowledgeRecord > KnowledgeMap
MADARA_EXPORT utility::Refcounter< logger::Logger > global_logger
ssize_t write_file(const std::string &filename, void *buffer, size_t size)
Writes a file with provided contents.
Definition: Utility.cpp:487
std::string & lower(std::string &input)
Converts the string to lower.
Definition: Utility.inl:89
MADARA_EXPORT void strncpy_safe(char *dst, const char *src, size_t dst_size)
Performs a strncpy in a way that will compile without warnings.
Definition: Utility.cpp:376
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:418
Copyright(c) 2020 Galois.