MADARA  3.4.1
KnowledgeRecord.inl
Go to the documentation of this file.
1 
2 
3 #ifndef _KNOWLEDGE_RECORD_INL_
4 #define _KNOWLEDGE_RECORD_INL_
5 
6 #include <algorithm>
7 #include <iostream>
8 #include <sstream>
9 #include <math.h>
10 
11 #include "madara/utility/Utility.h"
13 
21 namespace madara
22 {
23 namespace knowledge
24 {
26  : logger_(&logger)
27 {
28 }
29 
30 
31 template<typename T, utility::enable_if_<utility::is_int_numeric<T>(), int>>
33  T value, logger::Logger& logger) noexcept
34  : logger_(&logger), int_value_((Integer)value), type_(INTEGER)
35 {
36 }
37 
38 template<typename T,
39  typename std::enable_if<std::is_floating_point<T>::value, void*>::type>
41  T value, logger::Logger& logger) noexcept
42  : logger_(&logger), double_value_((double)value), type_(DOUBLE)
43 {
44 }
45 
47  const std::vector<Integer>& value, logger::Logger& logger)
48  : logger_(&logger)
49 {
50  set_value(value);
51 }
52 
54  std::vector<Integer>&& value, logger::Logger& logger) noexcept
55  : logger_(&logger)
56 {
57  set_value(std::move(value));
58 }
59 
61  std::unique_ptr<std::vector<Integer>> value,
62  logger::Logger& logger) noexcept
63  : logger_(&logger)
64 {
65  set_value(std::move(value));
66 }
67 
69  const std::vector<double>& value, logger::Logger& logger)
70  : logger_(&logger)
71 {
72  set_value(value);
73 }
74 
76  std::vector<double>&& value, logger::Logger& logger) noexcept
77  : logger_(&logger)
78 {
79  set_value(std::move(value));
80 }
81 
83  std::unique_ptr<std::vector<double>> value, logger::Logger& logger) noexcept
84  : logger_(&logger)
85 {
86  set_value(std::move(value));
87 }
88 
90  const std::string& value, logger::Logger& logger)
91  : logger_(&logger)
92 {
93  set_value(value);
94 }
95 
97  std::string&& value, logger::Logger& logger) noexcept
98  : logger_(&logger)
99 {
100  set_value(std::move(value));
101 }
102 
104  std::unique_ptr<std::string> value, logger::Logger& logger) noexcept
105  : logger_(&logger)
106 {
107  set_value(std::move(value));
108 }
109 
111  const char* value, logger::Logger& logger)
112  : logger_(&logger)
113 {
114  set_value(std::string(value));
115 }
116 
118  std::unique_ptr<std::vector<unsigned char>> value,
119  logger::Logger& logger) noexcept
120  : logger_(&logger)
121 {
122  set_file(std::move(value));
123 }
124 
126  const CircBuf& buffer, logger::Logger& logger)
127  : logger_(&logger)
128 {
130 }
131 
133  CircBuf&& buffer, logger::Logger& logger) noexcept
134  : logger_(&logger)
135 {
136  overwrite_circular_buffer(std::move(buffer));
137 }
139  : logger_(rhs.logger_),
140  clock(rhs.clock),
141  toi_(rhs.toi_),
142  quality(rhs.quality),
143  write_quality(rhs.write_quality),
144  type_(rhs.type_),
145  shared_(rhs.is_ref_counted() ? SHARED : OWNED)
146 {
147  if (rhs.type_ == EMPTY)
148  return;
149 
150  if (rhs.type_ == INTEGER)
151  int_value_ = rhs.int_value_;
152  else if (rhs.type_ == INTEGER_ARRAY)
153  new (&int_array_) std::shared_ptr<std::vector<Integer>>(rhs.int_array_);
154  else if (rhs.type_ == DOUBLE)
156  else if (rhs.type_ == DOUBLE_ARRAY)
157  new (&double_array_)
158  std::shared_ptr<std::vector<double>>(rhs.double_array_);
159  else if (is_string_type(rhs.type_))
160  new (&str_value_) std::shared_ptr<std::string>(rhs.str_value_);
161  else if (is_binary_file_type(rhs.type_))
162  new (&file_value_)
163  std::shared_ptr<std::vector<unsigned char>>(rhs.file_value_);
164  else if (rhs.type_ == BUFFER)
165  new (&buf_) std::shared_ptr<CircBuf>(rhs.buf_);
166 }
167 
169  knowledge::KnowledgeRecord&& rhs) noexcept
170  : logger_(std::move(rhs.logger_)),
171  clock(rhs.clock),
172  toi_(rhs.toi_),
173  quality(rhs.quality),
174  write_quality(rhs.write_quality),
175  type_(rhs.type_),
176  shared_(rhs.shared_)
177 {
178  if (rhs.type_ == EMPTY)
179  return;
180 
181  if (rhs.type_ == INTEGER)
182  int_value_ = rhs.int_value_;
183  else if (rhs.type_ == INTEGER_ARRAY)
184  new (&int_array_)
185  std::shared_ptr<std::vector<Integer>>(std::move(rhs.int_array_));
186  else if (rhs.type_ == DOUBLE)
187  double_value_ = rhs.double_value_;
188  else if (rhs.type_ == DOUBLE_ARRAY)
189  new (&double_array_)
190  std::shared_ptr<std::vector<double>>(std::move(rhs.double_array_));
191  else if (is_string_type(rhs.type_))
192  new (&str_value_) std::shared_ptr<std::string>(std::move(rhs.str_value_));
193  else if (is_binary_file_type(rhs.type_))
194  new (&file_value_)
195  std::shared_ptr<std::vector<unsigned char>>(std::move(rhs.file_value_));
196  else if (rhs.type_ == BUFFER)
197  new (&buf_) std::shared_ptr<CircBuf>(std::move(rhs.buf_));
198 
199  rhs.type_ = EMPTY;
200 }
201 
203 {
204  clear_union();
205 }
206 
208 {
209  logger_ = rhs.logger_;
210  clock = rhs.clock;
211  toi_ = rhs.toi_;
212  quality = rhs.quality;
214 }
215 
217 {
218  if (this == &rhs)
219  return;
220 
221  if (has_history())
222  {
223  KnowledgeRecord tmp = rhs.has_history() ? rhs.get_newest() : rhs;
224  emplace_hist(std::move(tmp));
225  }
226  else if (rhs.has_history())
227  {
228  overwrite(rhs.get_newest());
229  }
230  else
231  {
232  overwrite(rhs);
233  }
234 }
235 
237 {
238  if (this == &rhs)
239  return;
240 
241  if (!rhs.exists())
242  {
243  clear_value();
244  return;
245  }
246 
247  if (has_history())
248  {
249  KnowledgeRecord tmp =
250  rhs.has_history() ? std::move(rhs.ref_newest()) : std::move(rhs);
251  emplace_hist(std::move(tmp));
252  }
253  else if (rhs.has_history())
254  {
255  overwrite(std::move(rhs.ref_newest()));
256  }
257  else
258  {
259  overwrite(std::move(rhs));
260  }
261 }
262 
264 {
265  if (this == &rhs)
266  return;
267 
268  copy_metadata(rhs);
269  set_value(rhs);
270 }
271 
273 {
274  if (this == &rhs)
275  return;
276 
277  copy_metadata(rhs);
278  set_value(std::move(rhs));
279 }
280 
282 {
283  if (this == &rhs)
284  return;
285 
286  // clear any dynamic memory being used on the left hand side
287  clear_value();
288 
289  if (rhs.type_ == EMPTY)
290  return;
291 
292  // set the instance properties accordingly
293  type_ = rhs.type_;
295 
296  if (rhs.type_ == INTEGER)
297  int_value_ = rhs.int_value_;
298  else if (rhs.type_ == INTEGER_ARRAY)
299  new (&int_array_) std::shared_ptr<std::vector<Integer>>(rhs.int_array_);
300  else if (rhs.type_ == DOUBLE)
302  else if (rhs.type_ == DOUBLE_ARRAY)
303  new (&double_array_)
304  std::shared_ptr<std::vector<double>>(rhs.double_array_);
305  else if (is_string_type(rhs.type_))
306  new (&str_value_) std::shared_ptr<std::string>(rhs.str_value_);
307  else if (is_binary_file_type(rhs.type_))
308  new (&file_value_)
309  std::shared_ptr<std::vector<unsigned char>>(rhs.file_value_);
310  else if (rhs.type_ == BUFFER)
311  new (&buf_) std::shared_ptr<CircBuf>(rhs.buf_);
312 }
313 
315 {
316  if (this == &rhs)
317  return;
318 
319  // clear any dynamic memory being used on the left hand side
320  clear_value();
321 
322  if (rhs.type_ == EMPTY)
323  return;
324 
325  // set the instance properties accordingly
326  type_ = rhs.type_;
327  shared_ = rhs.shared_;
328 
329  if (rhs.type_ == INTEGER)
330  int_value_ = rhs.int_value_;
331  else if (rhs.type_ == INTEGER_ARRAY)
332  new (&int_array_)
333  std::shared_ptr<std::vector<Integer>>(std::move(rhs.int_array_));
334  else if (rhs.type_ == DOUBLE)
335  double_value_ = rhs.double_value_;
336  else if (rhs.type_ == DOUBLE_ARRAY)
337  new (&double_array_)
338  std::shared_ptr<std::vector<double>>(std::move(rhs.double_array_));
339  else if (is_string_type(rhs.type_))
340  new (&str_value_) std::shared_ptr<std::string>(std::move(rhs.str_value_));
341  else if (is_binary_file_type(rhs.type_))
342  new (&file_value_)
343  std::shared_ptr<std::vector<unsigned char>>(std::move(rhs.file_value_));
344  else if (rhs.type_ == BUFFER)
345  new (&buf_) std::shared_ptr<CircBuf>(std::move(rhs.buf_));
346 
347  rhs.type_ = EMPTY;
348 }
349 
351  const knowledge::KnowledgeRecord& rhs)
352 {
353  // copy fields not copied by overwrite
354  copy_metadata(rhs);
355 
356  overwrite(rhs);
357 
358  return *this;
359 }
360 
362  knowledge::KnowledgeRecord&& rhs) noexcept
363 {
364  // copy fields not copied by overwrite
365  copy_metadata(rhs);
366 
367  overwrite(std::move(rhs));
368 
369  return *this;
370 }
371 
373  const knowledge::KnowledgeRecord& rhs) const
374 {
375  return !(*this == rhs);
376 }
377 
381 inline bool KnowledgeRecord::operator!(void)const
382 {
383  return !is_true();
384 }
385 
390 {
391  KnowledgeRecord record(*this);
392 
393  if (type_ == INTEGER)
394  {
395  record.set_value(-int_value_);
396  }
397  else if (type_ == DOUBLE)
398  {
399  record.set_value(-double_value_);
400  }
401  else if (has_history())
402  {
403  record.set_value(-get_newest());
404  }
405 
406  return record;
407 }
408 
413  const knowledge::KnowledgeRecord& rhs)
414 {
415  if (is_integer_type(type_))
416  {
417  if (is_integer_type(rhs.type_))
418  set_value(to_integer() + rhs.to_integer());
419  else
420  set_value(to_integer() + rhs.to_double());
421  }
422  else if (is_double_type(type_))
423  set_value(to_double() + rhs.to_double());
424 
425  else if (is_string_type(type_))
426  set_value(to_string() + rhs.to_string());
427 
428  else if (has_history())
429  set_value(get_newest() + rhs);
430 
431  return *this;
432 }
433 
438 {
439  if (is_integer_type(type_))
440  set_value(to_integer() - 1);
441 
442  else if (is_double_type(type_))
443  set_value(to_double() - 1);
444 
445  else if (has_history())
446  {
447  KnowledgeRecord tmp = get_newest();
448  if (tmp.is_integer_type()) {
449  set_value(tmp.to_integer() - 1);
450  } else if (tmp.is_double_type()) {
451  set_value(tmp.to_double() - 1);
452  }
453  }
454 
455  return *this;
456 }
457 
462 {
463  if (is_integer_type(type_))
464  set_value(to_integer() + 1);
465 
466  else if (is_double_type(type_))
467  set_value(to_double() + 1);
468 
469  else if (has_history())
470  {
471  KnowledgeRecord tmp = get_newest();
472  if (tmp.is_integer_type()) {
473  set_value(tmp.to_integer() + 1);
474  } else if (tmp.is_double_type()) {
475  set_value(tmp.to_double() + 1);
476  }
477  }
478 
479  return *this;
480 }
481 
486  const knowledge::KnowledgeRecord& rhs)
487 {
488  if (is_integer_type(type_))
489  {
490  if (is_integer_type(rhs.type_))
491  set_value(to_integer() - rhs.to_integer());
492  else
493  set_value(to_integer() - rhs.to_double());
494  }
496  set_value(to_double() - rhs.to_double());
497 
498  else if (has_history())
499  set_value(get_newest() - rhs);
500 
501  return *this;
502 }
503 
508  const knowledge::KnowledgeRecord& rhs)
509 {
510  if (is_integer_type(type_))
511  {
512  if (is_integer_type(rhs.type_))
513  set_value(to_integer() * rhs.to_integer());
514  else
515  set_value(to_integer() * rhs.to_double());
516  }
518  set_value(to_double() * rhs.to_double());
519 
520  else if (has_history())
521  set_value(get_newest() * rhs);
522 
523  return *this;
524 }
525 
530  const knowledge::KnowledgeRecord& rhs)
531 {
532  if (is_integer_type(type_))
533  {
534  if (is_integer_type(rhs.type_))
535  {
536  Integer denom = rhs.to_integer();
537  if (denom == 0)
538  set_value(NAN);
539  else
540  set_value(to_integer() / denom);
541  }
542  else
543  {
544  double denom = rhs.to_double();
545 
546  if (denom == 0)
547  set_value(NAN);
548  else
549  set_value(to_integer() / denom);
550  }
551  }
553  {
554  double denom = rhs.to_double();
555 
556  if (denom == 0)
557  set_value(NAN);
558  else
559  set_value(to_double() / denom);
560  }
561 
562  else if (has_history())
563  set_value(get_newest() / rhs);
564 
565  return *this;
566 }
567 
572  const knowledge::KnowledgeRecord& rhs)
573 {
574  if (is_integer_type(type_))
575  {
576  if (is_integer_type(rhs.type_))
577  {
578  Integer denom = rhs.to_integer();
579  if (denom == 0)
580  set_value(NAN);
581  else
582  set_value(to_integer() % denom);
583  }
584  }
585 
586  else if (has_history())
587  set_value(get_newest() % rhs);
588 
589  return *this;
590 }
591 
596  const knowledge::KnowledgeRecord& rhs) const
597 {
598  // copy this value to a local copy
599  knowledge::KnowledgeRecord ret_value(*this);
600 
601  return ret_value *= rhs;
602 }
603 
608  const knowledge::KnowledgeRecord& rhs) const
609 {
610  // copy this value to a local copy
611  knowledge::KnowledgeRecord ret_value(*this);
612 
613  return ret_value /= rhs;
614 }
615 
620  const knowledge::KnowledgeRecord& rhs) const
621 {
622  // copy this value to a local copy
623  knowledge::KnowledgeRecord ret_value(*this);
624 
625  return ret_value %= rhs;
626 }
627 
632  const knowledge::KnowledgeRecord& rhs) const
633 {
634  // copy this value to a local copy
635  knowledge::KnowledgeRecord ret_value(*this);
636 
637  return ret_value += rhs;
638 }
639 
640 inline bool KnowledgeRecord::is_false(void) const
641 {
642  return !is_true();
643 }
644 
648 inline std::ostream& operator<<(
649  std::ostream& stream, const KnowledgeRecord& rhs)
650 {
651  if (rhs.type() &
653  {
654  stream << rhs.to_string(", ");
655  }
656  else
657  stream << rhs.to_string();
658 
659  return stream;
660 }
661 
666  const knowledge::KnowledgeRecord& rhs) const
667 {
668  // copy this value to a local copy
669  knowledge::KnowledgeRecord ret_value(*this);
670 
671  return ret_value -= rhs;
672 }
673 
674 inline void KnowledgeRecord::unshare(void)
675 {
676  if (shared_ != SHARED)
677  {
678  return;
679  }
680 
681  if (is_ref_counted())
682  {
683  if (is_string_type(type_))
684  {
686  }
687  else if (is_binary_file_type(type_))
688  {
690  }
691  else if (type_ == INTEGER_ARRAY)
692  {
694  }
695  else if (type_ == DOUBLE_ARRAY)
696  {
698  }
699  else if (type_ == BUFFER)
700  {
702  }
703  }
704  shared_ = OWNED;
705 }
706 
708 {
710 
711  result->unshare();
712 
713  return result;
714 }
715 
717 {
718  *this = source;
719  unshare();
720 }
721 
723 {
724  KnowledgeRecord ret(*this);
725  ret.unshare();
726  return ret;
727 }
728 
729 inline bool KnowledgeRecord::exists(void) const
730 {
731  return !(type_ == EMPTY || (type_ == BUFFER && buf_->empty()));
732 }
733 
734 inline int KnowledgeRecord::status(void) const
735 {
736  return type_ == EMPTY ? UNCREATED : MODIFIED;
737 }
738 
743 {
744  if (!exists())
745  {
746  set_value((Integer)0);
747  }
748 }
749 
750 inline uint32_t KnowledgeRecord::size(void) const
751 {
752  if (type_ == INTEGER || type_ == DOUBLE)
753  {
754  return 1;
755  }
756  else if (is_string_type(type_))
757  {
758  return (uint32_t)str_value_->size() + 1;
759  }
760  else if (is_binary_file_type(type_))
761  {
762  return (uint32_t)file_value_->size();
763  }
764  else if (type_ == INTEGER_ARRAY)
765  {
766  return (uint32_t)int_array_->size();
767  }
768  else if (type_ == DOUBLE_ARRAY)
769  {
770  return (uint32_t)double_array_->size();
771  }
772  else if (type_ == BUFFER)
773  {
774  return buf_->empty() ? 1 : ref_newest().size();
775  }
776  return 1;
777 }
778 
779 inline uint32_t KnowledgeRecord::type(void) const
780 {
781  return has_history() ? (buf_->empty() ? EMPTY : ref_newest().type_) : type_;
782 }
783 
784 inline bool KnowledgeRecord::set_type(uint32_t type)
785 {
786  if (type == type_ || (is_string_type(type_) && is_string_type(type)) ||
788  {
789  type_ = type;
790  return true;
791  }
792  else if (type_ == BUFFER)
793  {
794  if (buf_->empty())
795  {
796  buf_->emplace_back();
797  }
798 
799  return ref_newest().set_type(type);
800  }
801  return false;
802 }
803 
804 inline int64_t KnowledgeRecord::get_encoded_size(void) const
805 {
806  int64_t buffer_size(sizeof(type_) + sizeof(uint32_t) + sizeof(toi_) + 0);
807 
808  if (type_ == INTEGER)
809  {
810  buffer_size += sizeof(Integer);
811  }
812  else if (type_ == DOUBLE)
813  {
814  buffer_size += sizeof(double);
815  }
816  else if (type_ == INTEGER_ARRAY)
817  {
818  buffer_size += sizeof(Integer) * double_array_->size();
819  }
820  else if (type_ == DOUBLE_ARRAY)
821  {
822  buffer_size += sizeof(double) * double_array_->size();
823  }
824  else if (is_string_type(type_))
825  {
826  buffer_size += str_value_->size() + 1;
827  }
828  else if (is_binary_file_type(type_))
829  {
830  buffer_size += file_value_->size();
831  }
832  else if (type_ == BUFFER && !buf_->empty())
833  {
834  return ref_newest().get_encoded_size();
835  }
836 
837  return buffer_size;
838 }
839 
840 inline int64_t KnowledgeRecord::get_encoded_size(const std::string& key) const
841 {
842  // for keyed size, add another uint32_t and the size of the key with a null
843  // char
844  int64_t buffer_size(sizeof(uint32_t) * 1);
845  buffer_size += (key.size() + 1);
846 
847  // and then add the default encoded size
848  buffer_size += get_encoded_size();
849 
850  return buffer_size;
851 }
852 
853 inline bool KnowledgeRecord::is_ref_counted(void) const
854 {
855  return is_ref_counted(type_);
856 }
857 
859 {
860  return type != INTEGER && type != DOUBLE;
861 }
862 
863 inline bool KnowledgeRecord::is_string_type(void) const
864 {
865  return is_string_type(type());
866 }
867 
869 {
870  return type == STRING || type == XML || type == TEXT_FILE;
871 }
872 
873 inline bool KnowledgeRecord::is_double_type(void) const
874 {
875  return is_double_type(type());
876 }
877 
879 {
880  return type == DOUBLE || type == DOUBLE_ARRAY;
881 }
882 
883 inline bool KnowledgeRecord::is_integer_type(void) const
884 {
885  return is_integer_type(type());
886 }
887 
889 {
890  return type == EMPTY || type == INTEGER || type == INTEGER_ARRAY;
891 }
892 
893 inline bool KnowledgeRecord::is_array_type(void) const
894 {
895  return is_array_type(type());
896 }
897 
899 {
900  return (type & ALL_ARRAYS) != 0;
901 }
902 
903 inline bool KnowledgeRecord::is_image_type(void) const
904 {
905  return is_image_type(type());
906 }
907 
909 {
910  return type == IMAGE_JPEG;
911 }
912 
913 inline bool KnowledgeRecord::is_file_type(void) const
914 {
915  return is_file_type(type());
916 }
917 
918 inline bool KnowledgeRecord::is_file_type(uint32_t type)
919 {
920  return type == TEXT_FILE || type == XML || type == IMAGE_JPEG ||
922 }
923 
925 {
926  return is_binary_file_type(type());
927 }
928 
930 {
931  return type == IMAGE_JPEG || type == UNKNOWN_FILE_TYPE;
932 }
933 
934 inline uint32_t max_quality(const knowledge::KnowledgeRecords& records)
935 {
936  uint32_t max = 0;
937 
938  // iterate over the list and return the max
939  for (KnowledgeRecords::const_iterator i = records.begin(); i != records.end();
940  ++i)
941  {
942  max = std::max<uint32_t>(i->second->quality, max);
943  }
944  return max;
945 }
946 
947 inline uint32_t max_quality(const KnowledgeMap& records)
948 {
949  uint32_t max = 0;
950 
951  // iterate over the list and return the max
952  for (KnowledgeMap::const_iterator i = records.begin(); i != records.end();
953  ++i)
954  {
955  max = std::max<uint32_t>(i->second.quality, max);
956  }
957  return max;
958 }
959 
960 template<typename T>
961 inline void destruct(T& x)
962 {
963  x.~T();
964 }
965 
966 inline void KnowledgeRecord::clear_union(void) noexcept
967 {
968  if (type_ & ALL_CLEARABLES)
969  {
970  if (type_ == INTEGER_ARRAY)
971  destruct(int_array_);
972  else if (type_ == DOUBLE_ARRAY)
973  destruct(double_array_);
974  else if (is_string_type(type_))
975  destruct(str_value_);
976  else if (is_binary_file_type(type_))
977  destruct(file_value_);
978  else if (type_ == BUFFER)
979  destruct(buf_);
980  shared_ = OWNED;
981  }
982 }
983 
984 inline void KnowledgeRecord::clear_value(void) noexcept
985 {
986  clear_union();
987 
988  type_ = EMPTY;
989 }
990 
991 inline const char* KnowledgeRecord::read(
992  const char* buffer, int64_t& buffer_remaining)
993 {
994  // format is [key_size | key | type | value_size | value]
995 
996  uint32_t buff_value_size(0);
997  decltype(type_) type = INTEGER;
998  uint32_t size = 1;
999 
1000  // Remove the type of value from the buffer
1001  if (buffer_remaining >= (int64_t)sizeof(type))
1002  {
1003  memcpy(&type, buffer, sizeof(type));
1005  buffer += sizeof(type);
1006  }
1007  buffer_remaining -= sizeof(type);
1008 
1009  // Remove the size of value from the buffer
1010  if (buffer_remaining >= (int64_t)sizeof(size))
1011  {
1012  memcpy(&size, buffer, sizeof(size));
1014 
1015  if (is_integer_type(type))
1016  buff_value_size = size * sizeof(Integer);
1017  else if (is_double_type(type))
1018  buff_value_size = size * sizeof(double);
1019  else
1020  buff_value_size = size;
1021 
1022  buffer += sizeof(buff_value_size);
1023  }
1024  else
1025  {
1026  buffer_remaining = -1;
1027  return buffer;
1028  }
1029  buffer_remaining -= sizeof(buff_value_size);
1030 
1031  // Remove the toi from the buffer
1032  if (buffer_remaining >= (int64_t)sizeof(toi_))
1033  {
1034  memcpy(&toi_, buffer, sizeof(toi_));
1036  buffer += sizeof(toi_);
1037  }
1038  buffer_remaining -= sizeof(toi_);
1039 
1040  // madara_logger_ptr_log (logger_, logger::LOG_TRACE,
1041  //"KnowledgeRecord::read: reading type code %d\n", type);
1042  // madara_logger_ptr_log (logger_, logger::LOG_TRACE,
1043  //"KnowledgeRecord::read: reading type size %d (buf size %d)\n", size,
1044  // buff_value_size);
1045 
1046  // Remove the value from the buffer
1047  if (buffer_remaining >= int64_t(buff_value_size))
1048  {
1049  if (is_string_type(type))
1050  {
1051  if (buff_value_size >= 1)
1052  {
1053  emplace_string(buffer, buff_value_size - 1);
1054  }
1055  else
1056  {
1057  emplace_string();
1058  }
1059  }
1060 
1061  else if (type == INTEGER)
1062  {
1063  Integer tmp;
1064  memcpy(&tmp, buffer, sizeof(tmp));
1066  }
1067 
1068  else if (type == INTEGER_ARRAY)
1069  {
1070  std::vector<Integer> tmp;
1071  tmp.reserve(size);
1072 
1073  for (uint32_t i = 0; i < size; ++i)
1074  {
1075  Integer cur;
1076  memcpy(&cur, buffer + i * sizeof(cur), sizeof(cur));
1077  tmp.emplace_back(madara::utility::endian_swap(cur));
1078  }
1079 
1080  emplace_integers(std::move(tmp));
1081  }
1082 
1083  else if (type == DOUBLE)
1084  {
1085  double tmp;
1086  memcpy(&tmp, buffer, sizeof(tmp));
1088  }
1089 
1090  else if (type == DOUBLE_ARRAY)
1091  {
1092  std::vector<double> tmp;
1093  tmp.reserve(size);
1094 
1095  for (uint32_t i = 0; i < size; ++i)
1096  {
1097  double cur;
1098  memcpy(&cur, buffer + i * sizeof(cur), sizeof(cur));
1099  tmp.emplace_back(madara::utility::endian_swap(cur));
1100  }
1101 
1102  emplace_doubles(std::move(tmp));
1103  }
1104 
1105  else if (is_binary_file_type(type))
1106  {
1107  const unsigned char* b = (const unsigned char*)buffer;
1108  emplace_file(b, b + size);
1109  }
1110  else
1111  {
1112  buffer_remaining = -1;
1113  return buffer;
1114  }
1115 
1116  buffer += buff_value_size;
1117  buffer_remaining -= sizeof(char) * buff_value_size;
1118 
1119  type_ = type;
1120  }
1121 
1122  return buffer;
1123 }
1124 
1125 inline const char* KnowledgeRecord::read(
1126  const char* buffer, std::string& key, int64_t& buffer_remaining)
1127 {
1128  // format is [key_size | key | type | value_size | value]
1129 
1130  uint32_t key_size(0);
1131 
1132  // Remove the key size from the buffer
1133  if (buffer_remaining >= (int64_t)sizeof(key_size))
1134  {
1135  memcpy(&key_size, buffer, sizeof(key_size));
1136  key_size = madara::utility::endian_swap(key_size);
1137  buffer += sizeof(key_size);
1138  }
1139  buffer_remaining -= sizeof(key_size);
1140 
1141  // Remove the key from the buffer
1142  if (buffer_remaining >= int64_t(sizeof(char) * int64_t(key_size)))
1143  {
1144  if (key_size > 0)
1145  {
1146  // don't worry about null terminator
1147  key.assign(buffer, key_size - 1);
1148  }
1149  else
1150  {
1151  key.clear();
1152  }
1153 
1154  buffer += sizeof(char) * key_size;
1155  }
1156  buffer_remaining -= sizeof(char) * int64_t(key_size);
1157 
1158  // read the type and data
1159  buffer = read(buffer, buffer_remaining);
1160 
1161  return buffer;
1162 }
1163 
1164 inline const char* KnowledgeRecord::read(
1165  const char* buffer, uint32_t& key_id, int64_t& buffer_remaining)
1166 {
1167  // format is [key_id | type | value_size | value]
1168 
1169  // Remove the key size from the buffer
1170  if (buffer_remaining >= (int64_t)sizeof(key_id))
1171  {
1172  memcpy(&key_id, buffer, sizeof(key_id));
1173  key_id = madara::utility::endian_swap(key_id);
1174  buffer += sizeof(key_id);
1175  buffer_remaining -= sizeof(key_id);
1176 
1177  // read the type and data
1178  buffer = read(buffer, buffer_remaining);
1179  }
1180 
1181  return buffer;
1182 }
1183 
1184 // reset the to empty
1185 inline void KnowledgeRecord::reset_value(void) noexcept
1186 {
1187  clear_value();
1188 
1189  quality = 0;
1190  write_quality = 0;
1191  clock = 0;
1192  toi_ = 0;
1193 }
1194 
1195 // set the value_ to a string
1196 inline void KnowledgeRecord::set_value(std::string&& new_value)
1197 {
1198  emplace_string(std::move(new_value));
1199  type_ = STRING;
1200 }
1201 
1202 // set the value_ to a string
1203 inline void KnowledgeRecord::set_value(const std::string& new_value)
1204 {
1205  emplace_string(new_value);
1206  type_ = STRING;
1207 }
1208 
1209 // set the value_ to a string
1210 inline void KnowledgeRecord::set_value(std::unique_ptr<std::string> new_value)
1211 {
1212  emplace_shared_val<std::string, STRING, &KnowledgeRecord::str_value_>(
1213  std::move(new_value));
1214 }
1215 
1216 // set the value_ to a string
1217 inline void KnowledgeRecord::set_value(const char* new_value, uint32_t size)
1218 {
1219  emplace_string(new_value, size);
1220  type_ = STRING;
1221 }
1222 
1223 // set the value_ to a string
1224 inline void KnowledgeRecord::set_xml(const char* new_value, size_t size)
1225 {
1226  emplace_string(new_value, size);
1227  type_ = XML;
1228 }
1229 
1230 // set the value_ to a string
1231 inline void KnowledgeRecord::set_xml(std::string&& new_value)
1232 {
1233  emplace_string(std::move(new_value));
1234  type_ = XML;
1235 }
1236 
1237 // set the value_ to a string
1238 inline void KnowledgeRecord::set_xml(const std::string& new_value)
1239 {
1240  emplace_string(new_value);
1241  type_ = XML;
1242 }
1243 
1244 // set the value_ to a string
1245 inline void KnowledgeRecord::set_xml(std::unique_ptr<std::string> new_value)
1246 {
1247  emplace_shared_val<std::string, XML, &KnowledgeRecord::str_value_>(
1248  std::move(new_value));
1249 }
1250 
1251 // set the value_ to a string
1252 inline void KnowledgeRecord::set_text(const char* new_value, size_t size)
1253 {
1254  emplace_string(new_value, size);
1255  type_ = TEXT_FILE;
1256 }
1257 
1258 // set the value_ to a string
1259 inline void KnowledgeRecord::set_text(std::string&& new_value)
1260 {
1261  emplace_string(std::move(new_value));
1262  type_ = TEXT_FILE;
1263 }
1264 
1265 // set the value_ to a string
1266 inline void KnowledgeRecord::set_text(const std::string& new_value)
1267 {
1268  emplace_string(new_value);
1269  type_ = TEXT_FILE;
1270 }
1271 
1272 // set the value_ to a string
1273 inline void KnowledgeRecord::set_text(std::unique_ptr<std::string> new_value)
1274 {
1275  emplace_shared_val<std::string, TEXT_FILE, &KnowledgeRecord::str_value_>(
1276  std::move(new_value));
1277 }
1278 
1279 // set the value_ to a string
1281  const unsigned char* new_value, size_t size)
1282 {
1283  emplace_file(new_value, new_value + size);
1284  type_ = IMAGE_JPEG;
1285 }
1286 
1287 inline void KnowledgeRecord::set_jpeg(std::vector<unsigned char>&& new_value)
1288 {
1289  emplace_file(std::move(new_value));
1290  type_ = IMAGE_JPEG;
1291 }
1292 
1294  const std::vector<unsigned char>& new_value)
1295 {
1296  emplace_file(new_value);
1297  type_ = IMAGE_JPEG;
1298 }
1299 
1301  std::unique_ptr<std::vector<unsigned char>> new_value)
1302 {
1303  emplace_shared_vec<unsigned char, IMAGE_JPEG, &KnowledgeRecord::file_value_>(
1304  std::move(new_value));
1305 }
1306 
1307 // set the value_ to a string
1309  const unsigned char* new_value, size_t size)
1310 {
1311  emplace_file(new_value, new_value + size);
1313 }
1314 
1315 inline void KnowledgeRecord::set_file(std::vector<unsigned char>&& new_value)
1316 {
1317  emplace_file(std::move(new_value));
1319 }
1320 
1322  const std::vector<unsigned char>& new_value)
1323 {
1324  emplace_file(new_value);
1326 }
1327 
1329  std::unique_ptr<std::vector<unsigned char>> new_value)
1330 {
1331  emplace_shared_vec<unsigned char, UNKNOWN_FILE_TYPE,
1332  &KnowledgeRecord::file_value_>(std::move(new_value));
1333 }
1334 
1335 inline void KnowledgeRecord::set_value(Integer new_value)
1336 {
1337  if (has_history())
1338  {
1339  KnowledgeRecord tmp;
1340  tmp.copy_metadata(*this);
1341  tmp.set_value(new_value);
1342  set_value(std::move(tmp));
1343  return;
1344  }
1345  if (type_ != INTEGER)
1346  {
1347  clear_union();
1348  type_ = INTEGER;
1349  }
1350  int_value_ = new_value;
1351 }
1352 
1353 inline void KnowledgeRecord::set_value(int new_value)
1354 {
1355  if (has_history())
1356  {
1357  KnowledgeRecord tmp;
1358  tmp.copy_metadata(*this);
1359  tmp.set_value(new_value);
1360  set_value(std::move(tmp));
1361  return;
1362  }
1363  if (type_ != INTEGER)
1364  {
1365  clear_union();
1366  type_ = INTEGER;
1367  }
1368  int_value_ = (Integer)new_value;
1369 }
1370 
1371 inline void KnowledgeRecord::set_value(size_t new_value)
1372 {
1373  if (has_history())
1374  {
1375  KnowledgeRecord tmp;
1376  tmp.copy_metadata(*this);
1377  tmp.set_value(new_value);
1378  set_value(std::move(tmp));
1379  return;
1380  }
1381  if (type_ != INTEGER)
1382  {
1383  clear_union();
1384  type_ = INTEGER;
1385  }
1386  int_value_ = (Integer)new_value;
1387 }
1388 
1389 // set the value_ to a double
1390 inline void KnowledgeRecord::set_value(double new_value)
1391 {
1392  if (has_history())
1393  {
1394  KnowledgeRecord tmp;
1395  tmp.copy_metadata(*this);
1396  tmp.set_value(new_value);
1397  set_value(std::move(tmp));
1398  return;
1399  }
1400  if (type_ != DOUBLE)
1401  {
1402  clear_union();
1403  type_ = DOUBLE;
1404  }
1405  double_value_ = new_value;
1406 }
1407 
1408 // set the value_ to a float
1409 inline void KnowledgeRecord::set_value(float new_value)
1410 {
1411  if (has_history())
1412  {
1413  KnowledgeRecord tmp;
1414  tmp.copy_metadata(*this);
1415  tmp.set_value(new_value);
1416  set_value(std::move(tmp));
1417  return;
1418  }
1419  if (type_ != DOUBLE)
1420  {
1421  clear_union();
1422  type_ = DOUBLE;
1423  }
1424  double_value_ = (double)new_value;
1425 }
1426 
1427 // set the value_ to an array of doubles
1428 inline void KnowledgeRecord::set_value(const Integer* new_value, uint32_t size)
1429 {
1430  emplace_integers(new_value, new_value + size);
1431 }
1432 
1433 // set the value_ to an array of integers
1434 inline void KnowledgeRecord::set_value(std::vector<Integer>&& new_value)
1435 {
1436  emplace_integers(std::move(new_value));
1437 }
1438 
1439 // set the value_ to an array of integers
1440 inline void KnowledgeRecord::set_value(const std::vector<Integer>& new_value)
1441 {
1442  emplace_integers(new_value);
1443 }
1444 
1445 // set the value_ to an array of integers
1447  std::unique_ptr<std::vector<Integer>> new_value)
1448 {
1449  emplace_shared_vec<Integer, INTEGER_ARRAY, &KnowledgeRecord::int_array_>(
1450  std::move(new_value));
1451 }
1452 
1453 // set the value_ to an array of doubles
1454 inline void KnowledgeRecord::set_value(const double* new_value, uint32_t size)
1455 {
1456  emplace_doubles(new_value, new_value + size);
1457 }
1458 
1459 // set the value_ to an array of doubles
1460 inline void KnowledgeRecord::set_value(std::vector<double>&& new_value)
1461 {
1462  emplace_doubles(std::move(new_value));
1463 }
1464 
1465 // set the value_ to an array of doubles
1466 inline void KnowledgeRecord::set_value(const std::vector<double>& new_value)
1467 {
1468  emplace_doubles(new_value);
1469 }
1470 
1471 // set the value_ to an array of doubles
1473  std::unique_ptr<std::vector<double>> new_value)
1474 {
1475  emplace_shared_vec<double, DOUBLE_ARRAY, &KnowledgeRecord::double_array_>(
1476  std::move(new_value));
1477 }
1478 
1484 template<typename T, utility::enable_if_<utility::is_int_numeric<T>(), int>>
1485 inline void KnowledgeRecord::set_index(size_t index, T value)
1486 {
1487  if (has_history())
1488  {
1489  KnowledgeRecord tmp = get_newest();
1490  tmp.set_index(index, value);
1491  set_value(std::move(tmp));
1492  return;
1493  }
1494  if (type_ == DOUBLE_ARRAY)
1495  {
1496  // let the set_index for doubles take care of this
1497  set_index(index, double(value));
1498  return;
1499  }
1500  else if (type_ == INTEGER_ARRAY)
1501  {
1502  unshare();
1503 
1504  if (index >= int_array_->size())
1505  {
1506  int_array_->resize(index + 1);
1507  }
1508  }
1509  else
1510  {
1511  emplace_integers(index + 1);
1512  }
1513 
1514  int_array_->at(index) = value;
1515 }
1516 
1522 template<typename T,
1523  typename std::enable_if<std::is_floating_point<T>::value, void*>::type>
1524 inline void KnowledgeRecord::set_index(size_t index, T value)
1525 {
1526  if (has_history())
1527  {
1528  KnowledgeRecord tmp = get_newest();
1529  tmp.set_index(index, value);
1530  set_value(std::move(tmp));
1531  return;
1532  }
1533  if (type_ == INTEGER_ARRAY)
1534  {
1535  std::vector<double> tmp(int_array_->begin(), int_array_->end());
1536  emplace_doubles(std::move(tmp));
1537 
1538  if (index >= double_array_->size())
1539  {
1540  double_array_->resize(index + 1);
1541  }
1542  }
1543  else if (type_ != DOUBLE_ARRAY)
1544  {
1545  emplace_doubles(index + 1);
1546  }
1547  else
1548  {
1549  unshare();
1550 
1551  if (index >= double_array_->size())
1552  {
1553  double_array_->resize(index + 1);
1554  }
1555  }
1556 
1557  double_array_->at(index) = value;
1558 }
1559 
1560 
1561 
1562 inline std::shared_ptr<const std::string> KnowledgeRecord::share_string() const
1563 {
1564  if (is_string_type(type_))
1565  {
1566  shared_ = SHARED;
1567  return str_value_;
1568  }
1569  else if (has_history() && !buf_->empty())
1570  {
1571  return ref_newest().share_string();
1572  }
1573  return nullptr;
1574 }
1575 
1576 inline std::shared_ptr<const std::vector<KnowledgeRecord::Integer>>
1578 {
1579  if (type_ == INTEGER_ARRAY)
1580  {
1581  shared_ = SHARED;
1582  return int_array_;
1583  }
1584  else if (has_history() && !buf_->empty())
1585  {
1586  return ref_newest().share_integers();
1587  }
1588  return nullptr;
1589 }
1590 
1591 inline std::shared_ptr<const std::vector<double>>
1593 {
1594  if (type_ == DOUBLE_ARRAY)
1595  {
1596  shared_ = SHARED;
1597  return double_array_;
1598  }
1599  else if (has_history() && !buf_->empty())
1600  {
1601  return ref_newest().share_doubles();
1602  }
1603  return nullptr;
1604 }
1605 
1606 inline std::shared_ptr<const std::vector<unsigned char>>
1608 {
1610  {
1611  shared_ = SHARED;
1612  return file_value_;
1613  }
1614  else if (has_history() && !buf_->empty())
1615  {
1616  return ref_newest().share_binary();
1617  }
1618  return nullptr;
1619 }
1620 
1621 inline std::shared_ptr<KnowledgeRecord::CircBuf>
1623 {
1624  if (!has_history())
1625  {
1626  return nullptr;
1627  }
1628  shared_ = SHARED;
1629  return buf_;
1630 }
1631 
1632 inline KnowledgeRecord::operator bool(void) const
1633 {
1634  return is_true();
1635 }
1636 
1638  char* buffer, int64_t& buffer_remaining) const
1639 {
1640  if (has_history() && !buf_->empty())
1641  {
1642  return ref_newest().write(buffer, buffer_remaining);
1643  }
1644  // format is [type | value_size | value]
1645 
1646  char* size_location = 0;
1647  uint32_t size_intermediate = 0;
1648  uint32_t uint32_temp;
1649  Integer integer_temp;
1650  double double_temp;
1651  uint32_t size = this->size();
1652 
1653  int64_t encoded_size = get_encoded_size();
1654 
1655  if (buffer_remaining >= encoded_size)
1656  {
1658  "KnowledgeRecord::write:"
1659  " encoding %" PRId64 " byte message\n",
1660  encoded_size);
1661 
1662  // Remove the type of value from the buffer
1663  if (buffer_remaining >= (int64_t)sizeof(type_))
1664  {
1665  decltype(type_) tmp = madara::utility::endian_swap(type_);
1666  memcpy(buffer, &tmp, sizeof(tmp));
1667  buffer += sizeof(tmp);
1668  }
1669  buffer_remaining -= sizeof(type_);
1670 
1671  // Remove the size of value from the buffer
1672  if (buffer_remaining >= (int64_t)sizeof(size))
1673  {
1674  // set a pointer to size, in case we need to modify it during
1675  // value copy (e.g. during double conversion)
1676  size_location = buffer;
1677  size_intermediate = size;
1678 
1679  // note that we do not encode the size yet because it may change
1680  // and we need the architectural-specific version for other checks
1681 
1682  buffer += sizeof(size);
1683  }
1684  buffer_remaining -= sizeof(size);
1685 
1686  // Write TOI to buffer
1687  if (buffer_remaining >= (int64_t)sizeof(toi_))
1688  {
1689  decltype(toi_) tmp = madara::utility::endian_swap(toi_);
1690  memcpy(buffer, &tmp, sizeof(tmp));
1691  buffer += sizeof(tmp);
1692  }
1693  buffer_remaining -= sizeof(toi_);
1694 
1695  // Remove the value from the buffer
1696  if (is_string_type(type_))
1697  {
1698  // strings do not have to be converted
1699  if (buffer_remaining >= int64_t(size))
1700  {
1701  memcpy(buffer, &(*str_value_)[0], size);
1702  }
1703  }
1704  else if (type_ == INTEGER)
1705  {
1706  if (buffer_remaining >= int64_t(sizeof(Integer)))
1707  {
1708  integer_temp = madara::utility::endian_swap(int_value_);
1709  memcpy(buffer, &integer_temp, sizeof(integer_temp));
1710 
1711  size_intermediate = sizeof(Integer);
1712  }
1713  }
1714  else if (type_ == INTEGER_ARRAY)
1715  {
1716  if (buffer_remaining >= int64_t(size * sizeof(Integer)))
1717  {
1718  // convert integers to network byte order
1719  const Integer* ptr_temp = &(*int_array_)[0];
1720  Integer* target_buffer = (Integer*)buffer;
1721 
1722  for (uint32_t i = 0; i < size; ++i, ++ptr_temp, ++target_buffer)
1723  {
1724  integer_temp = madara::utility::endian_swap(*ptr_temp);
1725  memcpy(target_buffer, &integer_temp, sizeof(Integer));
1726  }
1727 
1728  size_intermediate = size * sizeof(Integer);
1729  }
1730  }
1731  else if (type_ == DOUBLE)
1732  {
1733  if (buffer_remaining >= int64_t(sizeof(double)))
1734  {
1736  memcpy(buffer, &double_temp, sizeof(double));
1737 
1738  size_intermediate = sizeof(double);
1739  }
1740  }
1741  else if (type_ == DOUBLE_ARRAY)
1742  {
1743  if (buffer_remaining >= int64_t(size * sizeof(double)))
1744  {
1745  // convert integers to network byte order
1746  const double* ptr_temp = &(*double_array_)[0];
1747  double* target_buffer = (double*)buffer;
1748 
1749  for (uint32_t i = 0; i < size; ++i, ++ptr_temp, ++target_buffer)
1750  {
1751  double_temp = madara::utility::endian_swap(*ptr_temp);
1752  memcpy(target_buffer, &double_temp, sizeof(double_temp));
1753  }
1754 
1755  size_intermediate = size * sizeof(double);
1756 
1767  }
1768  }
1769  else if (is_binary_file_type(type_))
1770  {
1771  // strings do not have to be converted
1772  if (buffer_remaining >= size)
1773  {
1774  memcpy(buffer, &(*file_value_)[0], size);
1775  }
1776  }
1777 
1778  if (size_location)
1779  {
1780  buffer_remaining -= size_intermediate;
1781  buffer += size_intermediate;
1782 
1783  uint32_temp = madara::utility::endian_swap(size);
1784  memcpy(size_location, &uint32_temp, sizeof(uint32_temp));
1785  }
1786  }
1787  else
1788  {
1789  std::stringstream local_buffer;
1790  local_buffer << "KnowledgeRecord::write: ";
1791  local_buffer << encoded_size << " byte encoding cannot fit in ";
1792  local_buffer << buffer_remaining << " byte buffer\n";
1793 
1795  logger_, logger::LOG_ERROR, local_buffer.str().c_str());
1796 
1797  throw exceptions::MemoryException(local_buffer.str());
1798  }
1799  return buffer;
1800 }
1801 
1803  char* buffer, const std::string& key, int64_t& buffer_remaining) const
1804 
1805 {
1806  // format is [key_size | key | type | value_size | value]
1807 
1808  uint32_t key_size = uint32_t(key.size() + 1);
1809  uint32_t uint32_temp;
1810 
1811  int64_t encoded_size = get_encoded_size(key);
1812 
1813  if (buffer_remaining >= encoded_size)
1814  {
1816  "KnowledgeRecord::write:"
1817  " encoding %" PRId64 " byte message\n",
1818  encoded_size);
1819 
1820  // Remove the key size from the buffer
1821  if (buffer_remaining >= (int64_t)sizeof(key_size))
1822  {
1823  uint32_temp = madara::utility::endian_swap(key_size);
1824  memcpy(buffer, &uint32_temp, sizeof(uint32_temp));
1825  buffer += sizeof(key_size);
1826  }
1827  buffer_remaining -= sizeof(key_size);
1828 
1829  // Remove the key from the buffer
1830  if (buffer_remaining >= (int64_t)sizeof(char) * key_size)
1831  {
1832  // copy the string and set null terminator in buffer
1833  utility::strncpy_safe(buffer, key.c_str(), key_size);
1834 
1835  buffer += sizeof(char) * key_size;
1836  }
1837  buffer_remaining -= sizeof(char) * key_size;
1838 
1839  // write the type and value of the record
1840  buffer = write(buffer, buffer_remaining);
1841  }
1842  else
1843  {
1844  std::stringstream local_buffer;
1845  local_buffer << "KnowledgeRecord::write: ";
1846  local_buffer << encoded_size << " byte encoding cannot fit in ";
1847  local_buffer << buffer_remaining << " byte buffer\n";
1848 
1849  madara_logger_ptr_log(logger_, logger::LOG_ERROR, local_buffer.str().c_str());
1850 
1851  throw exceptions::MemoryException(local_buffer.str());
1852  }
1853  return buffer;
1854 }
1855 
1857  char* buffer, uint32_t key_id, int64_t& buffer_remaining) const
1858 {
1859  // format is [key_id | type | value_size | value]
1860 
1861  uint32_t uint32_temp;
1862 
1863  int64_t encoded_size = get_encoded_size() + sizeof(key_id);
1864 
1865  if (buffer_remaining >= encoded_size)
1866  {
1868  "KnowledgeRecord::write:"
1869  " encoding %" PRId64 " byte message\n",
1870  encoded_size);
1871 
1872  // write the key id to the buffer
1873  if (buffer_remaining >= (int64_t)sizeof(key_id))
1874  {
1875  uint32_temp = madara::utility::endian_swap(key_id);
1876  memcpy(buffer, &uint32_temp, sizeof(uint32_temp));
1877  buffer += sizeof(key_id);
1878  }
1879  buffer_remaining -= sizeof(key_id);
1880 
1881  // write the type and value of the record
1882  buffer = write(buffer, buffer_remaining);
1883  }
1884  else
1885  {
1886  std::stringstream local_buffer;
1887  local_buffer << "KnowledgeRecord::write: ";
1888  local_buffer << encoded_size << " byte encoding cannot fit in ";
1889  local_buffer << buffer_remaining << " byte buffer\n";
1890 
1891  madara_logger_ptr_log(logger_, logger::LOG_ERROR, local_buffer.str().c_str());
1892 
1893  throw exceptions::MemoryException(local_buffer.str());
1894  }
1895  return buffer;
1896 }
1897 }
1898 }
1899 
1900 #endif // _KNOWLEDGE_RECORD_INL_
#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
An exception for general memory errors like out-of-memory.
This class encapsulates an entry in a KnowledgeBase.
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_
KnowledgeRecord operator/(const KnowledgeRecord &rhs) const
Divides operator.
void set_xml(const char *new_value, size_t size)
sets the value to an xml string
bool set_type(uint32_t type)
Modify the type, but only if it's compatible with current type without changing any actual data store...
KnowledgeRecord operator%(const KnowledgeRecord &rhs) const
Modulus operator.
void emplace_file(Args &&... args)
Construct a file (vector of unsigned char) within this KnowledgeRecord.
uint32_t type(void) const
returns the type of the value
KnowledgeRecord & operator*=(const KnowledgeRecord &rhs)
In-place multiplication operator.
void set_full(const KnowledgeRecord &new_value)
Sets the value and meta data from another KnowledgeRecord.
void copy_metadata(const KnowledgeRecord &new_value)
Set metadata of this record equal to that of new_value, but doesn't change value.
std::shared_ptr< std::vector< unsigned char > > file_value_
char * write(char *buffer, int64_t &buffer_remaining) const
Writes a KnowledgeRecord instance to a buffer and updates the amount of buffer room remaining.
KnowledgeRecord & operator/=(const KnowledgeRecord &rhs)
In-place division operator.
void emplace_doubles(Args &&... args)
Construct a vector of doubles within this KnowledgeRecord.
int64_t get_encoded_size(void) const
Returns the encoded size of the record.
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.
bool is_image_type(void) const
returns true if the knowledge record has an image type
uint64_t clock
last modification lamport clock time
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.
uint32_t write_quality
write priority for any local updates
bool is_true(void) const
Checks to see if the record is true.
size_t get_newest(OutputIterator out, size_t count) const
Copy the count newest stored history entries of this record to the given output iterator,...
bool shared_
is this knowledge record's shared_ptr, if any, exposed to outside holders?
void overwrite(const KnowledgeRecord &new_value)
Clears everything including history, but excluding metadata (e.g., toi, clock) and copies value from ...
KnowledgeRecord & operator--(void)
Predecrement operator.
std::shared_ptr< const std::vector< double > > share_doubles() const
KnowledgeRecord operator-(void) const
Negate.
bool is_ref_counted(void) const
returns if the record has a reference-counted type
bool operator!(void) const
Logical not.
bool operator!=(const KnowledgeRecord &rhs) const
Unequal to.
int status(void) const
returns the status of the record.
KnowledgeRecord deep_copy() const
Creates a deep copy of this knowledge record.
std::shared_ptr< CircBuf > share_circular_buffer() const
Get a shared_ptr to the history buffer inside this record.
void set_jpeg(const unsigned char *new_value, size_t size)
sets the value to a jpeg
uint32_t size(void) const
returns the size of the value
std::shared_ptr< const std::vector< unsigned char > > share_binary() const
std::shared_ptr< std::vector< Integer > > int_array_
bool exists(void) const
Checks if record exists (i.e., is not uncreated)
void set_text(const char *new_value, size_t size)
sets the value to a plaintext string
bool is_integer_type(void) const
returns if the record is a integer type (INTEGER, INTEGER_ARRAY)
KnowledgeRecord * clone(void) const
clones the record.
bool is_binary_file_type(void) const
returns true if the knowledge record has a binary file type
uint32_t type_
type of variable (INTEGER, DOUBLE, STRING, FILE, IMAGE)
Integer to_integer(void) const
converts the value to an integer.
KnowledgeRecord & operator%=(const KnowledgeRecord &rhs)
In-place modulus operator.
bool is_string_type(void) const
returns true if the record is a string type (STRING, XML, TEXT_FILE)
KnowledgeRecord & operator-=(const KnowledgeRecord &rhs)
In-place subtraction operator.
void set_modified(void)
sets the status to modified
std::shared_ptr< const std::vector< Integer > > share_integers() const
KnowledgeRecord get_newest() const
Return the newest stored history entry of this record.
void emplace_string(Args &&... args)
Construct a string within this KnowledgeRecord.
KnowledgeRecord operator+(const KnowledgeRecord &rhs) const
Plus operator.
KnowledgeRecord & operator=(const KnowledgeRecord &rhs)
Assignment.
std::shared_ptr< const std::vector< T > > emplace_shared_vec(Args &&... args)
KnowledgeRecord operator*(const KnowledgeRecord &rhs) const
Times operator.
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_
KnowledgeRecord & operator++(void)
Preincrement operator.
logger::Logger * logger_
the logger used for any internal debugging information
uint32_t quality
priority of the update
KnowledgeRecord & operator+=(const KnowledgeRecord &rhs)
In-place addition operator.
void reset_value(void) noexcept
resets the variable to an integer
bool is_file_type(void) const
returns true if the knowledge record has a file type
bool is_array_type(void) const
returns if the record is an array type (DOUBLE_ARRAY, INTEGER_ARRAY)
KnowledgeRecord & emplace_hist(Args &&... args)
int64_t get_encoded_size(const std::string &key) const
Returns the encoded size of the record.
std::shared_ptr< const std::string > share_string() const
void overwrite_circular_buffer(Args &&... args)
Construct a CircularBuffer within this KnowledgeRecord directly.
void set_file(const unsigned char *new_value, size_t size)
sets the value to an unknown file type
bool is_false(void) const
Checks to see if the record is false.
const char * read(const char *buffer, int64_t &buffer_remaining)
Reads a KnowledgeRecord instance from a buffer and updates the amount of buffer room remaining.
void unshare(void)
If this record holds a shared_ptr, make a copy of the underlying value so it has an exclusive copy.
uint64_t toi_
last modification system clock time
A multi-threaded logger for logging to one or more destinations.
Definition: Logger.h:165
General purpose circular buffer container.
constexpr string_t string
Provides functions and classes for the distributed knowledge base.
::std::map< std::string, KnowledgeRecord * > KnowledgeRecords
uint32_t max_quality(const KnowledgeRecords &records)
Returns the maximum quality within the records.
std::ostream & operator<<(std::ostream &stream, const KnowledgeRecord &rhs)
output stream buffering
::std::map< std::string, KnowledgeRecord > KnowledgeMap
Provides knowledge logging services to files and terminals.
Definition: GlobalLogger.h:12
uint64_t endian_swap(uint64_t value)
Converts a host format uint64_t into big endian.
Definition: Utility.inl:134
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
Copyright(c) 2020 Galois.