MADARA  3.2.3
KnowledgeCast.h
Go to the documentation of this file.
1 
56 #ifndef _MADARA_KNOWLEDGE_KNOWLEDGE_CAST_H_
57 #define _MADARA_KNOWLEDGE_KNOWLEDGE_CAST_H_
58 
59 #include <string>
60 #include <cstring>
61 #include <type_traits>
62 #include <stdbool.h>
65 
66 namespace madara { namespace knowledge {
67 
71 template<class T>
72 class type {};
73 
74 #ifdef DOXYGEN
75 
91 template<class Out>
92 inline Out knowledge_cast(const KnowledgeRecord &in);
93 
112 template<class Out>
113 inline Out knowledge_cast(type<T> t, const KnowledgeRecord &in);
114 
115 template<class Out>
136 inline Out &knowledge_cast(const KnowledgeRecord &in, Out &out);
137 
148 template<class In>
149 inline KnowledgeRecord knowledge_cast(const In &in);
150 
151 #else
152 
155 template<class O>
156 inline auto knowledge_cast(type<O>, const KnowledgeRecord &in) ->
157  typename std::enable_if<std::is_constructible<O,
158  const KnowledgeRecord &>::value, O>::type
159 {
160  return O{in};
161 }
162 
164 template<class O>
165 inline auto knowledge_cast(type<O>, const KnowledgeRecord &in) ->
166  typename std::enable_if<std::is_floating_point<O>::value, O>::type
167 {
168  return static_cast<O>(in.to_double());
169 }
170 
172 template<class O>
173 inline auto knowledge_cast(type<O>, const KnowledgeRecord &in) ->
174  typename std::enable_if<std::is_integral<O>::value, O>::type
175 {
176  return static_cast<O>(in.to_integer());
177 }
178 
180 inline bool knowledge_cast(type<bool>, const KnowledgeRecord &in)
181 {
182  return in.is_true();
183 }
184 
187 {
188  return in.to_string();
189 }
190 
192 inline std::vector<int64_t> knowledge_cast(type<std::vector<int64_t>>,
193  const KnowledgeRecord &in)
194 {
195  return in.to_integers();
196 }
197 
199 template<typename T>
200 inline auto knowledge_cast(type<std::vector<T>>, const KnowledgeRecord &in) ->
201  typename std::enable_if<std::is_integral<T>::value, std::vector<T>>::type
202 {
203  auto vec = in.to_integers();
204  return {std::begin(vec), std::end(vec)};
205 }
206 
208 inline std::vector<double> knowledge_cast(type<std::vector<double>>, const KnowledgeRecord &in)
209 {
210  return in.to_doubles();
211 }
212 
214 template<typename T>
215 inline auto knowledge_cast(type<std::vector<T>>, const KnowledgeRecord &in) ->
216  typename std::enable_if<std::is_floating_point<T>::value, std::vector<T>>::type
217 {
218  auto vec = in.to_doubles();
219  return {std::begin(vec), std::end(vec)};
220 }
221 
224 namespace impl {
225  template<typename T>
226  inline auto get_size(const T &c) -> decltype(c.size()) {
227  return c.size();
228  }
229 
230  template<typename T, size_t N>
231  inline size_t get_size(const T (&arr)[N]) {
232  (void)arr;
233  return N;
234  }
235 
236  MADARA_MAKE_VAL_SUPPORT_TEST(resize, x, x.resize(size_t{}));
237 
238  template<typename T>
239  inline auto resize_or_clear(T &c, size_t n) ->
240  typename std::enable_if<!supports_resize<T&>::value,
241  decltype(c[0], get_size(c), size_t{})>::type
242  {
243  using elem_type = typename std::decay<decltype(c[0])>::type;
244  size_t curn = get_size(c);
245  for (; n < curn; ++n) {
246  c[n] = elem_type{};
247  }
248  return curn;
249  }
250 
251  template<typename T>
252  inline auto resize_or_clear(T &c, size_t n) ->
253  typename std::enable_if<supports_resize<T&>::value, size_t>::type
254  {
255  c.resize(n);
256  return n;
257  }
258 
259  template<typename T>
260  inline auto share_array(const KnowledgeRecord &in) ->
261  typename std::enable_if<std::is_integral<
262  typename std::decay<decltype(*std::begin(std::declval<T&>()))>::type>::value,
263  decltype(in.share_integers())>::type
264  {
265  return in.share_integers();
266  }
267 
268  template<typename T>
269  inline auto to_array(const KnowledgeRecord &in) ->
270  typename std::enable_if<std::is_integral<
271  typename std::decay<decltype(*std::begin(std::declval<T&>()))>::type>::value,
272  decltype(in.to_integers())>::type
273  {
274  return in.to_integers();
275  }
276 
277  template<typename T>
278  inline auto share_array(const KnowledgeRecord &in) ->
279  typename std::enable_if<std::is_floating_point<
280  typename std::decay<decltype(*std::begin(std::declval<T&>()))>::type>::value,
281  decltype(in.share_doubles())>::type
282  {
283  return in.share_doubles();
284  }
285 
286  template<typename T>
287  inline auto to_array(const KnowledgeRecord &in) ->
288  typename std::enable_if<std::is_floating_point<
289  typename std::decay<decltype(*std::begin(std::declval<T&>()))>::type>::value,
290  decltype(in.to_doubles())>::type
291  {
292  return in.to_doubles();
293  }
294 
295  template<typename T>
296  struct simple_span
297  {
298  T *ptr;
299  size_t len;
300 
301  T *begin() const { return ptr; }
302  const T *cbegin() const { return ptr; }
303  T *end() const { return ptr + len; }
304  const T *cend() const { return ptr + len; }
305 
306  T &operator[](size_t i) const { return ptr[i]; }
307 
308  size_t size() const { return len; }
309  };
310 
311  template<typename T>
312  simple_span<T> make_span(T* ptr, size_t size) {
313  return {ptr, size};
314  }
315 
316  MADARA_MAKE_VAL_SUPPORT_TEST(target_container, x,
317  (std::is_arithmetic<typename std::decay<
318  decltype(*std::begin(x))>::type>::value,
319  impl::get_size(x)));
320 }
321 
324 template<typename T>
325 inline auto knowledge_cast(const KnowledgeRecord &in, T &out) ->
326  typename std::enable_if<!impl::supports_target_container<T&>::value,
327  decltype(out = knowledge_cast(type<T>{}, in))>::type
328 {
329  return (out = knowledge_cast(type<T>{}, in));
330 }
331 
332 namespace impl {
333  template <typename T>
334  struct is_basic_string : std::false_type {};
335 
336  template<typename CharT, typename Traits, typename Allocator>
337  struct is_basic_string<std::basic_string<CharT, Traits, Allocator>> :
338  std::true_type {};
339 }
340 
342 template<typename CharT, typename Traits, typename Allocator>
343 inline std::basic_string<CharT, Traits, Allocator> &knowledge_cast(
344  const KnowledgeRecord &in,
345  std::basic_string<CharT, Traits, Allocator> & out)
346 {
347  static_assert(std::is_same<std::string,
348  std::basic_string<CharT, Traits, Allocator>>::value,
349  "knowledge_cast only supports std::string, "
350  "not other std::basic_string types");
351  return (out = knowledge_cast(type<std::string>{}, in));
352 }
353 
356 template<typename T>
357 inline auto knowledge_cast(const KnowledgeRecord &in, T &out) ->
358  typename std::enable_if<
359  impl::supports_target_container<T&>::value &&
360  !impl::is_basic_string<T>::value,
361  decltype(out)>::type
362 {
363  auto ints = impl::share_array<T>(in);
364  if (ints) {
365  size_t count = ints->size();
366  count = std::min(impl::resize_or_clear(out, count), count);
367  std::copy_n (std::begin(*ints), count, std::begin(out));
368  } else {
369  auto ints_arr = impl::to_array<T>(in);
370  size_t count = ints_arr.size();
371  count = std::min(impl::resize_or_clear(out, count), count);
372  std::copy_n (std::begin(ints_arr), count, std::begin(out));
373  }
374  return out;
375 }
376 
379 template<typename T>
380 inline auto knowledge_cast(const KnowledgeRecord &in, T *out, size_t size)
381  -> decltype(knowledge_cast(in, std::declval<impl::simple_span<T>&>()),
382  (T*)nullptr)
383 {
384  auto span = impl::make_span(out, size);
385  knowledge_cast(in, span);
386  return out;
387 }
388 
391  const KnowledgeRecord &in)
392 {
393  return in;
394 }
395 
397 template<typename T>
398 inline auto knowledge_cast(const KnowledgeRecord &in) ->
399  decltype(knowledge_cast(type<T>{}, in)) {
400  return knowledge_cast(type<T>{}, in);
401 }
402 
406 template<class O>
407 inline auto knowledge_cast(O &&in) ->
408  typename std::decay<decltype(KnowledgeRecord{std::forward<O>(in)})>::type
409 {
410  return KnowledgeRecord{std::forward<O>(in)};
411 }
412 
415 template<typename T>
416 inline auto knowledge_cast(const T &in) ->
417  typename std::enable_if<
418  std::is_integral<typename std::decay<decltype(in[0])>::type>::value &&
419  !std::is_same<typename std::decay<decltype(in[0])>::type, char>::value &&
420  !std::is_same<typename std::decay<decltype(in[0])>::type,
421  unsigned char>::value &&
422  !std::is_same<T, std::vector<int64_t>>::value,
423  typename std::decay<decltype(KnowledgeRecord{
424  tags::integers, std::begin(in), std::end(in)})>::type>::type
425 {
426  return KnowledgeRecord{tags::integers, std::begin(in), std::end(in)};
427 }
428 
430 template<typename T>
431 inline auto knowledge_cast(const T &in) ->
432  typename std::enable_if<
433  std::is_floating_point<typename std::decay<decltype(in[0])>::type>::value &&
434  !std::is_same<T, std::vector<double>>::value,
435  typename std::decay<decltype(KnowledgeRecord{
436  tags::doubles, std::begin(in), std::end(in)})>::type>::type
437 {
438  return KnowledgeRecord{tags::doubles, std::begin(in), std::end(in)};
439 }
440 
442 template<typename T>
443 inline auto knowledge_cast(const T &in) ->
444  typename std::enable_if<
445  std::is_same<typename std::decay<decltype(in[0])>::type, char>::value &&
446  !std::is_same<T, std::string>::value,
447  typename std::decay<decltype(KnowledgeRecord{
448  tags::string, std::begin(in), std::end(in)})>::type>::type
449 {
450  return KnowledgeRecord{tags::string, std::begin(in), std::end(in)};
451 }
452 
454 template<typename T>
455 inline auto knowledge_cast(const T &in) ->
456  typename std::enable_if<
457  std::is_same<typename std::decay<decltype(in[0])>::type, unsigned char>::value &&
458  !std::is_same<T, std::vector<unsigned char>>::value,
459  typename std::decay<decltype(KnowledgeRecord{
460  tags::binary, std::begin(in), std::end(in)})>::type>::type
461 {
462  return KnowledgeRecord{tags::binary, std::begin(in), std::end(in)};
463 }
464 
467 {
468  return in;
469 }
470 
472 inline const KnowledgeRecord &knowledge_cast(const KnowledgeRecord &in)
473 {
474  return in;
475 }
476 
477 #endif // !DOXYGEN
478 
481 #define MADARA_KNOWLEDGE_COMPARE_OP(op) \
482  template<typename T, \
483  typename std::enable_if<!std::is_convertible<T, KnowledgeRecord>::value && \
484  std::is_fundamental<T>::value, void *>::type = nullptr> \
485  inline auto operator op (const KnowledgeRecord &l, const T &r) -> \
486  decltype(knowledge_cast<T>(l) op r) \
487  { \
488  return knowledge_cast<T>(l) op r; \
489  } \
490  \
491  template<typename T, \
492  typename std::enable_if<!std::is_convertible<T, KnowledgeRecord>::value && \
493  std::is_fundamental<T>::value, void *>::type = nullptr> \
494  inline auto operator op (const T &l, const KnowledgeRecord &r) -> \
495  decltype(l op knowledge_cast<T>(r)) \
496  { \
497  return l op knowledge_cast<T>(r); \
498  } \
499  \
500  inline bool operator op (const KnowledgeRecord &l, std::nullptr_t) \
501  { \
502  return l op 0; \
503  } \
504  \
505  inline bool operator op (const KnowledgeRecord &l, const char *r) \
506  { \
507  auto s = l.share_string(); \
508  if (s) { \
509  return s->compare(r) op 0; \
510  } else { \
511  return l.to_string().compare(r) op 0; \
512  } \
513  } \
514  \
515  inline bool operator op (const char *l, const KnowledgeRecord &r) \
516  { \
517  auto s = r.share_string(); \
518  if (s) { \
519  return std::strcmp(l, s->c_str()) op 0; \
520  } else { \
521  return std::strcmp(l, r.to_string().c_str()) op 0; \
522  } \
523  } \
524  \
525  inline bool operator op (const KnowledgeRecord &l, const std::string &r) \
526  { \
527  auto s = l.share_string(); \
528  if (s) { \
529  return s->compare(r) op 0; \
530  } else { \
531  return l.to_string().compare(r) op 0; \
532  } \
533  } \
534  \
535  inline bool operator op (const std::string &l, const KnowledgeRecord &r) \
536  { \
537  auto s = r.share_string(); \
538  if (s) { \
539  return l.compare(*s) op 0; \
540  } else { \
541  return l.compare(r.to_string()) op 0; \
542  } \
543  }
544 
551 
554 #define MADARA_KNOWLEDGE_BINARY_OP(op) \
555  template<typename T, \
556  typename std::enable_if<!std::is_convertible<T, KnowledgeRecord>::value && \
557  std::is_fundamental<T>::value, void *>::type = nullptr> \
558  inline auto operator op (const KnowledgeRecord &l, const T &r) -> \
559  decltype(l op knowledge_cast(r)) \
560  { \
561  return l op knowledge_cast(r); \
562  } \
563  \
564  template<typename T, \
565  typename std::enable_if<!std::is_convertible<T, KnowledgeRecord>::value && \
566  std::is_fundamental<T>::value, void *>::type = nullptr> \
567  inline auto operator op (const T &l, const KnowledgeRecord &r) -> \
568  decltype(knowledge_cast(l) op r) \
569  { \
570  return knowledge_cast(l) op r; \
571  }
572 
578 
581 #define MADARA_KNOWLEDGE_COMPOSITE_OP(op) \
582  template<typename T, \
583  typename std::enable_if<!std::is_convertible<T, KnowledgeRecord>::value && \
584  std::is_fundamental<T>::value, void *>::type = nullptr> \
585  inline auto operator op (KnowledgeRecord &l, const T &r) -> \
586  decltype(l op knowledge_cast(r)) \
587  { \
588  return l op knowledge_cast(r); \
589  }
590 
596 
597 } }
598 
599 #endif
This class encapsulates an entry in a KnowledgeBase.
bool is_true(void) const
Checks to see if the record is true.
#define MADARA_KNOWLEDGE_BINARY_OP(op)
Generates binary math operators for KnowledgeRecords, in combination with types that can be knowledge...
std::shared_ptr< std::vector< double > > share_doubles() const
helper type for specifying template type parameters using a function argument instead of inside expli...
Definition: KnowledgeCast.h:72
double to_double(void) const
converts the value to a float/double.
std::shared_ptr< std::vector< Integer > > share_integers() const
static struct madara::knowledge::tags::doubles_t doubles
static struct madara::knowledge::tags::string_t string
std::vector< double > to_doubles(void) const
converts the value to a vector of doubles
Integer to_integer(void) const
converts the value to an integer.
static struct madara::knowledge::tags::integers_t integers
#define MADARA_MAKE_VAL_SUPPORT_TEST(name, var, expr)
Macro which generates feature testing traits, to allow enabling features based on what a given type s...
Definition: SupportTest.h:38
#define MADARA_KNOWLEDGE_COMPARE_OP(op)
Generates comparison operators for KnowledgeRecords, in combination with types that can be knowledge_...
#define MADARA_KNOWLEDGE_COMPOSITE_OP(op)
Generates composite assignment operators for KnowledgeRecords, in combination with types that can be ...
std::vector< Integer > to_integers(void) const
converts the value to a vector of integers
Provides functions and classes for the distributed knowledge base.
Out knowledge_cast(const KnowledgeRecord &in)
Convert a KnowledgeRecord into a specified type.
Copyright (c) 2015 Carnegie Mellon University.
std::string to_string(const std::string &delimiter=", ") const
converts the value to a string.
static struct madara::knowledge::tags::binary_t binary