Derecho  0.9
Distributed systems toolkit for RDMA
SerializationSupport.hpp
Go to the documentation of this file.
1 #pragma once
3 #include "context_ptr.hpp"
4 #include <cstring>
5 #include <mutils/macro_utils.hpp>
6 #include <mutils/mutils.hpp>
7 #include <mutils/tuple_extras.hpp>
8 #include <mutils/type_utils.hpp>
9 #include <tuple>
10 #include <vector>
11 
12 // BEGIN DECLARATIONS AND USAGE INFORMATION
13 
14 namespace mutils {
15 
16 // forward declaration
17 struct DeserializationManager;
18 
35  virtual std::size_t to_bytes(char* v) const = 0;
36 
46  virtual void post_object(
47  const std::function<void(char const* const, std::size_t)>&) const = 0;
48 
56  virtual std::size_t bytes_size() const = 0;
57 
58 #ifdef MUTILS_DEBUG
59 
66  virtual void ensure_registered(DeserializationManager&) = 0;
67 #endif
68  virtual ~ByteRepresentable() {}
69 
79  // needs to exist, but can't declare virtual statics
80  // virtual static std::unique_ptr<T> from_bytes(DeserializationManager *p,
81  // const char *v) const = 0;
82 
95  // needs to exist, but can't declare virtual statics
96  // virtual static context_ptr<T> from_bytes_noalloc(DeserializationManager *p,
97  // const char *v) const = 0;
98 };
99 
111 };
112 
113 // a pointer to a RemoteDeserializationContext. This exists
114 // so that I can switch it out with smart pointer types when
115 // debugging stuff.
117 
118 // a vector of RemoteDeserializationContext*.
119 // it's got a using declaration for the same reason
120 // as the above.
121 using RemoteDeserialization_v = std::vector<RemoteDeserializationContext_p>;
122 
142 
144 
146  : registered_v(std::move(o.registered_v)) {}
147 
149  registered_v.emplace_back(ctx);
150  return *this;
151  }
152 
158  template <typename T>
159  T& mgr() {
160  for(auto& candidate : registered_v) {
161  if(auto* t = dynamic_cast<T*>(candidate))
162  return *t;
163  }
164  assert(false && "Error: no registered manager exists");
165  struct dead_code {};
166  throw dead_code{};
167  }
168 
172  template <typename T>
173  const T& mgr() const {
174  for(auto& candidate : registered_v) {
175  if(auto* t = dynamic_cast<T*>(candidate))
176  return t;
177  }
178  assert(false && "Error: no registered manager exists");
179  struct dead_code {};
180  throw dead_code{};
181  }
182 
187  template <typename T>
188  bool registered() const {
189  for(auto& candidate : registered_v) {
190  if(dynamic_cast<T const*>(candidate))
191  return true;
192  }
193  return false;
194  }
195 };
196 
200 template <typename T, restrict2(std::is_pod<T>::value)>
201 auto bytes_size(const T&) {
202  return sizeof(T);
203 }
204 
210 std::size_t bytes_size(const ByteRepresentable& b);
211 
215 std::size_t bytes_size(const std::string& b);
216 
217 template <typename... T>
218 std::size_t bytes_size(const std::tuple<T...>& t);
219 
223 template <typename T, typename V>
224 std::size_t bytes_size(const std::pair<T, V>& pair) {
225  return bytes_size(pair.first) + bytes_size(pair.second);
226 }
227 
231 std::size_t bytes_size(const std::vector<bool>& v);
232 
233 template <typename T>
234 std::size_t bytes_size(const std::vector<T>& v) {
235  whenmutilsdebug(
236  static const auto typenonce_size = bytes_size(
237  type_name<std::vector<T>>());) if(std::is_pod<T>::value) return v
238  .size()
239  * bytes_size(v.back())
240  + sizeof(int) whenmutilsdebug(+typenonce_size);
241  else {
242  int accum = 0;
243  for(auto& e : v)
244  accum += bytes_size(e);
245  return accum + sizeof(int) whenmutilsdebug(+typenonce_size);
246  }
247 }
248 
253 template <typename T>
254 std::size_t bytes_size(const std::list<T>& list) {
255  if(std::is_pod<T>::value)
256  return list.size() * bytes_size(list.back()) + sizeof(int);
257  else {
258  int accum = 0;
259  for(const auto& e : list)
260  accum += bytes_size(e);
261  return accum + sizeof(int);
262  }
263 }
264 
268 template <typename T>
269 std::size_t bytes_size(const std::set<T>& s) {
270  int size = sizeof(int);
271  for(auto& a : s) {
272  size += bytes_size(a);
273  }
274  return size;
275 }
276 
281 template <typename K, typename V>
282 std::size_t bytes_size(const std::map<K, V>& m) {
283  int size = sizeof(int);
284  for(const auto& p : m) {
285  size += bytes_size(p.first);
286  size += bytes_size(p.second);
287  }
288  return size;
289 }
290 
294 template <typename... T>
295 std::size_t bytes_size_helper(const T&... t) {
296  return (bytes_size(t) + ... + 0);
297 }
298 template <typename... T>
299 std::size_t bytes_size(const std::tuple<T...>& t) {
300  return std::apply(bytes_size_helper<T...>, t);
301 }
302 
309 template <typename F, typename BR, typename... Args>
310 std::enable_if_t<std::is_pod<BR>::value> post_object(const F& f, const BR& br,
311  Args&&... args) {
312  f(std::forward<Args>(args)..., (char*)&br, sizeof(BR));
313 }
314 
315 void post_object(const std::function<void(char const* const, std::size_t)>& f,
316  const ByteRepresentable& br);
317 
318 #ifdef MUTILS_DEBUG
319 
323 void ensure_registered(ByteRepresentable& b, DeserializationManager& dm);
324 
329 template <typename T, restrict(std::is_pod<T>::value)>
330 void ensure_registered(const T&, DeserializationManager&) {}
331 #endif
332 
340 std::size_t to_bytes(const ByteRepresentable& b, char* v);
341 
346 std::size_t to_bytes(const std::string& b, char* v);
347 
353 template <typename T>
354 std::enable_if_t<std::is_base_of<ByteRepresentable CMA T>::value,
355  std::unique_ptr<T>>
356 from_bytes(DeserializationManager* ctx, char const* v) {
357  return T::from_bytes(ctx, v);
358 }
359 
365 template <typename T>
366 std::enable_if_t<std::is_pod<T>::value, std::unique_ptr<std::decay_t<T>>>
367 from_bytes(DeserializationManager*, char const* v);
368 
374 template <typename T>
375 std::enable_if_t<std::is_base_of<ByteRepresentable CMA std::decay_t<T>>::value,
378  DeserializationManager* ctx, const char* v,
379  context_ptr<std::decay_t<T>> = context_ptr<std::decay_t<T>>{}) {
381 }
382 template <typename T>
383 std::enable_if_t<std::is_base_of<ByteRepresentable CMA std::decay_t<T>>::value,
386  DeserializationManager* ctx, char const* const v,
387  context_ptr<const std::decay_t<T>> = context_ptr<const std::decay_t<T>>{}) {
388  // Uncomment the stuff below if we ever get a chance to use a recent g++
389  // if constexpr (std::is_const<T>::value ){
390  return std::decay_t<T>::from_bytes_noalloc_const(ctx, v);
391  //}
392  // else return std::decay_t<T>::from_bytes_noalloc(ctx,v);
393 }
394 
401 template <typename T>
402 std::enable_if_t<std::is_pod<T>::value, context_ptr<std::decay_t<T>>>
404 
405 template <typename T>
406 std::enable_if_t<std::is_pod<T>::value, context_ptr<const std::decay_t<T>>>
407 from_bytes_noalloc(DeserializationManager*, char const* const v,
409 
415 template <typename T, typename F>
416 auto deserialize_and_run(DeserializationManager* dsm, char* v, const F& fun);
417 
422 struct marshalled : public ByteRepresentable {
423  const std::size_t size;
424  char const* const data;
425 
426  marshalled(decltype(size) size, decltype(data) data)
427  : size(size), data(data) {}
428 
429  std::size_t to_bytes(char* v) const {
430  assert(false && "revisit this");
431  std::memcpy(v, data, size);
432  return size;
433  }
434  std::size_t bytes_size() const { return size; }
435 
436 #ifdef MUTILS_DEBUG
437 
438  void ensure_registered(DeserializationManager&) {}
439 
440 #endif
441 
442  template <typename DSM>
443  static std::unique_ptr<marshalled> from_bytes(DSM const* const,
444  char const* const) {
445  static_assert(std::is_same<DSM, void>::value && !std::is_same<DSM, void>::value,
446  "Do not deserialize into a marshalled. please.");
447  return nullptr;
448  }
449 
451  from_bytes_noalloc(DeserializationManager const* const, char* v);
452 };
453 
462 // end forward-declaring; everything past this point is implementation,
463 // and not essential to understanding the interface.
464 
475 std::function<void(char const* const, std::size_t)>
476 post_to_buffer(std::size_t& index, char* dest_buf);
477 
478 // post_object definitions -- must come before to_bytes definitions that use
479 // them
480 void post_object(const std::function<void(char const* const, std::size_t)>& f,
481  const std::string& str);
482 
483 template <typename T, typename V>
484 void post_object(const std::function<void(char const* const, std::size_t)>& f,
485  const std::pair<T, V>& pair) {
486  post_object(f, pair.first);
487  post_object(f, pair.second);
488 }
489 
490 template <typename... T>
492  const std::function<void(char const* const, std::size_t)>& f,
493  const T&... t) {
494  (post_object(f, t), ...);
495 }
496 
497 template <typename... T>
498 void post_object(const std::function<void(char const* const, std::size_t)>& f,
499  const std::tuple<T...>& t) {
500  //std::apply(std::bind(post_object_helper<T...>,f,/*variadic template?*/), t);
501  std::apply([f](T... args) {
502  post_object_helper(f, args...);
503  },
504  t);
505 }
506 
507 void post_object(const std::function<void(char const* const, std::size_t)>& f,
508  const std::vector<bool>& vec);
509 
510 template <typename T>
511 void post_object(const std::function<void(char const* const, std::size_t)>& f,
512  const std::vector<T>& vec) {
513  whenmutilsdebug(post_object(f, type_name<std::vector<T>>());) int size = vec.size();
514  f((char*)&size, sizeof(size));
515  if(std::is_pod<T>::value) {
516  std::size_t size = vec.size() * bytes_size(vec.back());
517  f((char*)vec.data(), size);
518  } else {
519  for(const auto& e : vec) {
520  post_object(f, e);
521  }
522  }
523 }
524 
525 template <typename T>
526 void post_object(const std::function<void(char const* const, std::size_t)>& f,
527  const std::list<T>& list) {
528  int size = list.size();
529  f((char*)&size, sizeof(size));
530  for(const auto& e : list) {
531  post_object(f, e);
532  }
533 }
534 
535 template <typename T>
536 void post_object(const std::function<void(char const* const, std::size_t)>& f,
537  const std::set<T>& s) {
538  int size = s.size();
539  f((char*)&size, sizeof(size));
540  for(const auto& a : s) {
541  post_object(f, a);
542  }
543 }
544 
545 template <typename K, typename V>
546 void post_object(const std::function<void(char const* const, std::size_t)>& f,
547  const std::map<K, V>& map) {
548  int size = map.size();
549  f((char*)&size, sizeof(size));
550  for(const auto& pair : map) {
551  post_object(f, pair.first);
552  post_object(f, pair.second);
553  }
554 }
555 
556 // end post_object section
557 
558 // to_bytes definitions -- these must come after bytes_size and post_object
559 // definitions To reduce code duplication, these are all implemented in terms of
560 // post_object
561 
565 template <typename T, restrict(std::is_pod<T>::value)>
566 std::size_t to_bytes(const T& t, char* v) {
567  auto res = std::memcpy(v, &t, sizeof(T));
568  assert(res);
569  (void)res;
570  return sizeof(T);
571 }
572 
573 std::size_t to_bytes(const std::vector<bool>& vec, char* v);
574 
575 template <typename T>
576 std::size_t to_bytes(const std::vector<T>& vec, char* v) {
577  auto size = bytes_size(vec);
578  std::size_t index = 0;
579  post_object(post_to_buffer(index, v), vec);
580  return size;
581 }
582 
583 template <typename T>
584 std::size_t to_bytes(const std::list<T>& list, char* buffer) {
585  auto size = bytes_size(list);
586  std::size_t offset = 0;
587  post_object(post_to_buffer(offset, buffer), list);
588  return size;
589 }
590 
591 template <typename T, typename V>
592 std::size_t to_bytes(const std::pair<T, V>& pair, char* buffer) {
593  std::size_t index = 0;
594  post_object(post_to_buffer(index, buffer), pair);
595  return bytes_size(pair);
596 }
597 
598 template <typename... T>
599 std::size_t to_bytes(const std::tuple<T...>& tuple, char* buffer) {
600  std::size_t index = 0;
601  post_object(post_to_buffer(index, buffer), tuple);
602  return bytes_size(tuple);
603 }
604 
605 template <typename T>
606 std::size_t to_bytes(const std::set<T>& s, char* _v) {
607  std::size_t index = 0;
608  auto size = bytes_size(s);
609  post_object(post_to_buffer(index, _v), s);
610  return size;
611 }
612 
613 template <typename K, typename V>
614 std::size_t to_bytes(const std::map<K, V>& m, char* buffer) {
615  std::size_t index = 0;
616  std::size_t size = bytes_size(m);
617  post_object(post_to_buffer(index, buffer), m);
618  return size;
619 }
620 // end to_bytes section
621 
622 #ifdef MUTILS_DEBUG
623 // ensure_registered definitions -- these could go anywhere since they don't
624 // depend on any other functions
625 void ensure_registered(const std::vector<bool>& v, DeserializationManager& dm);
626 template <typename T>
627 void ensure_registered(const std::vector<T>& v, DeserializationManager& dm) {
628  for(auto& e : v)
629  ensure_registered(e, dm);
630 }
631 
632 template <typename L, typename R>
633 void ensure_registered(const std::pair<L, R>& v, DeserializationManager& dm) {
634  ensure_registered(v.first, dm);
635  ensure_registered(v.second, dm);
636 }
637 
638 template <typename T>
639 void ensure_registered(const std::set<T>& v, DeserializationManager& dm) {
640  for(auto& e : v)
641  ensure_registered(e, dm);
642 }
643 
644 template <typename T>
645 void ensure_registered(const std::list<T>& v, DeserializationManager& dm) {
646  for(auto& e : v)
647  ensure_registered(e, dm);
648 }
649 // end ensure_registered section
650 #endif
651 
652 // from_string definition
653 
654 template <typename T>
655 std::unique_ptr<type_check<std::is_integral, T>>
656 from_string(DeserializationManager*, char const* v, std::size_t length) {
657  return std::make_unique<T>(std::stoll(std::string{v, length}));
658 }
659 
660 template <typename T>
661 std::unique_ptr<type_check<std::is_floating_point, T>>
662 from_string(DeserializationManager*, char const* v, std::size_t length) {
663  return std::make_unique<T>(std::stold(std::string{v, length}));
664 }
665 
666 template <typename>
667 struct is_string : std::false_type {};
668 
669 template <>
670 struct is_string<std::string> : std::true_type {};
671 
672 template <>
673 struct is_string<const std::string> : std::true_type {};
674 
675 template <typename T>
676 std::unique_ptr<type_check<is_string, T>>
677 from_string(DeserializationManager*, char const* v, std::size_t length) {
678  return std::make_unique<T>(std::string{v, length});
679 }
680 
681 // from_bytes definitions
682 template <typename T>
683 std::enable_if_t<std::is_pod<T>::value, std::unique_ptr<std::decay_t<T>>>
685  using T2 = std::decay_t<T>;
686  if(v) {
687  auto t = std::make_unique<T2>(*(T2*)v);
688  // std::memcpy(t.get(),v,sizeof(T));
689  return std::move(t);
690  } else
691  return nullptr;
692 }
693 
694 template <typename T>
695 std::enable_if_t<std::is_pod<T>::value, context_ptr<std::decay_t<T>>>
698  using T2 = std::decay_t<T>;
699  return context_ptr<T2>{(T2*)v};
700 }
701 
702 template <typename T>
703 std::enable_if_t<std::is_pod<T>::value, context_ptr<const std::decay_t<T>>>
705  context_ptr<T>) {
706  using T2 = std::decay_t<T>;
707  return context_ptr<const T2>{(const T2*)v};
708 }
709 
710 // Templates that become true_type when matched to the thing they identify,
711 // or become false_type if they fail to match, similar to std::is_pod
712 
713 template <typename>
714 struct is_pair : std::false_type {};
715 
716 template <typename T, typename U>
717 struct is_pair<std::pair<T, U>> : std::true_type {};
718 
719 /* use the definition in mutils/tuple_extras.hpp +21
720 template <typename> struct is_tuple : std::false_type {};
721 
722 template <typename...T>
723 struct is_tuple<std::tuple<T...>> : std::true_type {};
724 */
725 
726 template <typename>
727 struct is_list : std::false_type {};
728 
729 template <typename T>
730 struct is_list<std::list<T>> : std::true_type {};
731 
732 template <typename>
733 struct is_map : std::false_type {};
734 
735 template <typename K, typename V>
736 struct is_map<std::map<K, V>> : std::true_type {};
737 
738 template <typename T>
739 std::unique_ptr<type_check<is_string, T>> from_bytes(DeserializationManager*,
740  char const* v) {
741  assert(v);
742  return std::make_unique<T>(v);
743 }
744 
745 template <typename T>
749  assert(v);
750  return context_ptr<T>(new std::string{v});
751 }
752 
753 template <typename T>
754 std::unique_ptr<type_check<is_set, T>> from_bytes(DeserializationManager* ctx,
755  const char* _v) {
756  int size = ((int*)_v)[0];
757  const char* v = _v + sizeof(int);
758  auto r = std::make_unique<std::set<typename T::key_type>>();
759  for(int i = 0; i < size; ++i) {
760  auto e = from_bytes<typename T::key_type>(ctx, v);
761  v += bytes_size(*e);
762  r->insert(*e);
763  }
764  return std::move(r);
765 }
766 
767 template <typename T>
771  return context_ptr<T>{from_bytes<T>(ctx, v).release()};
772 }
773 
774 template <typename T>
775 std::unique_ptr<type_check<is_pair, T>> from_bytes(DeserializationManager* ctx,
776  const char* v) {
777  using ft = typename T::first_type;
778  using st = typename T::second_type;
779  auto fst = from_bytes_noalloc<ft>(ctx, v);
780  return std::make_unique<std::pair<ft, st>>(
781  *fst, *from_bytes_noalloc<st>(ctx, v + bytes_size(*fst)));
782 }
783 
784 template <typename L>
785 std::unique_ptr<type_check<is_list, L>> from_bytes(DeserializationManager* ctx,
786  const char* buffer) {
787  using elem = typename L::value_type;
788  int size = ((int*)buffer)[0];
789  const char* buf_ptr = buffer + sizeof(int);
790  std::unique_ptr<std::list<elem>> return_list{new L()};
791  for(int i = 0; i < size; ++i) {
792  context_ptr<elem> item = from_bytes_noalloc<elem>(ctx, buf_ptr, context_ptr<elem>{});
793  buf_ptr += bytes_size(*item);
794  return_list->push_back(*item);
795  }
796  return std::move(return_list);
797 }
798 
799 template <typename T>
803  return context_ptr<T>{from_bytes<T>(ctx, v).release()};
804 }
805 
806 template <typename T>
807 std::unique_ptr<T> boolvec_from_bytes(DeserializationManager* ctx,
808  char const* v);
809 
810 template <typename TupleType, std::size_t N>
811 auto from_bytes_helper(DeserializationManager* ctx, char const* v) {
812  using ElementType = typename std::tuple_element<N, TupleType>::type;
813  ElementType e(*from_bytes<ElementType>(ctx, v));
814  auto t = std::make_tuple<ElementType>(std::move(e));
815  if constexpr((N + 1) == std::tuple_size<TupleType>::value) {
816  return t;
817  } else {
818  return std::tuple_cat(t, from_bytes_helper<TupleType, N + 1>(ctx, v + bytes_size(std::get<0>(t))));
819  }
820 }
821 
822 template <typename T>
823 std::unique_ptr<type_check<is_tuple, T>> from_bytes(DeserializationManager* ctx, char const* v) {
824  return std::make_unique<T>(std::move(from_bytes_helper<T, 0>(ctx, v)));
825 }
826 
827 // Note: T is the type of the vector, not the vector's type parameter T
828 template <typename T>
829 std::enable_if_t<is_vector<T>::value, std::unique_ptr<T>>
830 from_bytes(DeserializationManager* ctx, char const* v) {
831 #ifdef MUTILS_DEBUG
832  const static std::string typenonce = type_name<T>();
833  const auto typenonce_size = bytes_size(typenonce);
834  auto remote_string = *from_bytes<std::string>(ctx, v);
835  if(typenonce != remote_string) {
836  std::cout << typenonce << std::endl
837  << std::endl;
838  std::cout << remote_string << std::endl;
839  }
840  assert(typenonce == v);
841  assert(typenonce == remote_string);
842  v += typenonce_size;
843 #endif
844  using member = typename T::value_type;
845  if(std::is_same<bool, member>::value) {
846  return boolvec_from_bytes<T>(ctx, v);
847  } else if(std::is_pod<member>::value && !std::is_same<bool, member>::value) {
848  member const* const start = (member*)(v + sizeof(int));
849  const int size = ((int*)v)[0];
850  return std::unique_ptr<T>{new T{start, start + size}};
851  } else {
852  int size = ((int*)v)[0];
853  auto* v2 = v + sizeof(int);
854  std::size_t accumulated_offset = 0;
855  std::unique_ptr<std::vector<member>> accum{new T()};
856  for(int i = 0; i < size; ++i) {
857  std::unique_ptr<member> item = from_bytes<member>(ctx, v2 + accumulated_offset);
858  accumulated_offset += bytes_size(*item);
859  accum->push_back(*item);
860  }
861  return accum;
862  }
863 }
864 
865 template <typename T>
869  return context_ptr<T>{from_bytes<T>(ctx, v).release()};
870 }
871 
872 template <typename T>
873 std::enable_if_t<is_map<T>::value, std::unique_ptr<T>>
874 from_bytes(DeserializationManager* ctx, char const* buffer) {
875  using key_t = typename T::key_type;
876  using value_t = typename T::mapped_type;
877  int size = ((int*)buffer)[0];
878  const char* buf_ptr = buffer + sizeof(int);
879 
880  auto new_map = std::make_unique<T>();
881  for(int i = 0; i < size; ++i) {
882  auto key = from_bytes_noalloc<key_t>(ctx, buf_ptr, context_ptr<key_t>{});
883  buf_ptr += bytes_size(*key);
884  auto value = from_bytes_noalloc<value_t>(ctx, buf_ptr, context_ptr<value_t>{});
885  buf_ptr += bytes_size(*value);
886  new_map->emplace(*key, *value);
887  }
888  return std::move(new_map);
889 }
890 
891 template <typename T>
895  return context_ptr<T>{from_bytes<T>(ctx, v).release()};
896 }
897 
905 std::size_t to_bytes_v(char*);
906 
907 template <typename T, typename... Rest>
908 std::size_t to_bytes_v(char* buf, const T& first, const Rest&... rest) {
909  auto size = to_bytes(first, buf);
910  return size + to_bytes_v(buf + size, rest...);
911 }
912 
913 std::size_t from_bytes_v(DeserializationManager*, char const* const);
914 
915 template <typename T, typename... Rest>
916 std::size_t from_bytes_v(DeserializationManager* dsm, char const* const buf,
917  std::unique_ptr<T>& first, Rest&... rest) {
918  first = from_bytes<T>(dsm, buf);
919  auto size = bytes_size(*first);
920  return size + from_bytes_v(dsm, buf + size, rest...);
921 }
922 
923 std::size_t from_bytes_noalloc_v(DeserializationManager*, char const* const);
924 
925 template <typename T, typename... Rest>
927  context_ptr<T>& first,
928  context_ptr<Rest>&... rest) {
929  first = from_bytes_noalloc<T>(dsm, buf, context_ptr<T>{});
930  auto size = bytes_size(*first);
931  return size + from_bytes_noalloc_v(dsm, buf + size, rest...);
932 }
933 
934 template <typename T, typename... Rest>
935 std::size_t from_bytes_noalloc_v(DeserializationManager* dsm, char* buf,
936  context_ptr<T>& first,
937  context_ptr<Rest>&... rest) {
938  return from_bytes_noalloc_v_nc(dsm, buf, first, rest...);
939 }
940 
941 template <typename T, typename... Rest>
943  char const* const buf,
944  context_ptr<const T>& first,
945  context_ptr<const Rest>&... rest) {
946  first = from_bytes_noalloc<const T>(dsm, buf, context_ptr<const T>{});
947  auto size = bytes_size(*first);
948  return size + from_bytes_noalloc_v(dsm, buf + size, rest...);
949 }
950 
951 // sample of how this might work. Nocopy, plus complete memory safety, but
952 // at the cost of callback land.
953 
954 struct dsr_info {
955  std::chrono::nanoseconds to_callfunc;
956  std::chrono::nanoseconds to_exit;
957  typename std::chrono::high_resolution_clock::time_point start_time;
958 };
959 #ifdef SERIALIZATION_STATS
960 inline auto& get_dsr_info() {
961  static thread_local dsr_info ret;
962  return ret;
963 }
964 #endif
965 template <typename F, typename R, typename... Args>
966 auto deserialize_and_run(DeserializationManager* dsm, char const* const v,
967  const F& fun, std::function<R(Args...)> const* const) {
968 #ifdef SERIALIZATION_STATS
969  using namespace std;
970  using namespace chrono;
971  static thread_local auto deserialize_and_run_start = high_resolution_clock::now();
972  static thread_local auto callfunc_time = deserialize_and_run_start;
973  struct on_function_end {
974  ~on_function_end() {
975  auto& r = get_dsr_info();
976  r.start_time = deserialize_and_run_start;
977  r.to_callfunc = callfunc_time - deserialize_and_run_start;
978  r.to_exit = high_resolution_clock::now() - deserialize_and_run_start;
979  }
980  };
981  on_function_end ofe;
982  deserialize_and_run_start = high_resolution_clock::now();
983 #endif
984  using result_t = std::result_of_t<F(Args...)>;
985  static_assert(std::is_same<result_t, R>::value,
986  "Error: function types mismatch.");
987  using fun_t = std::function<result_t(Args...)>;
988  // ensure implicit conversion can run
989  static_assert(
990  std::is_convertible<F, fun_t>::value,
991  "Error: type mismatch on function and target deserialialized type");
992  std::tuple<DeserializationManager*, const char*,
994  args_tuple;
995  std::get<0>(args_tuple) = dsm;
996  std::get<1>(args_tuple) = v;
997  // Make a pointer to from_bytes_noalloc_v with concrete argument types, to
998  // help the compiler
999  using from_bytes_type = std::size_t (*)(DeserializationManager*, const char*,
1001  from_bytes_type from_bytes_noalloc_concrete =
1002  [](DeserializationManager* d, const char* c,
1004  return from_bytes_noalloc_v(d, c, args...);
1005  };
1006  // Unmarshall fun's arguments into the context_ptrs
1007  /*auto size = */ callFunc(from_bytes_noalloc_concrete, args_tuple);
1008  // Call fun, but ignore the first two arguments in args_tuple
1009  return callFunc(
1010  [&fun](const auto&, const auto&, auto&... ctx_ptrs) {
1011 #ifdef SERIALIZATION_STATS
1012  callfunc_time = high_resolution_clock::now();
1013 #endif
1014  return fun(*ctx_ptrs...);
1015  },
1016  args_tuple);
1017 }
1018 
1019 template <typename F>
1020 auto deserialize_and_run(DeserializationManager* dsm, char const* const v,
1021  const F& fun) {
1022  using fun_t = std::decay_t<decltype(convert(fun))>;
1023  return deserialize_and_run<F>(dsm, v, fun, (fun_t*)nullptr);
1024 }
1025 
1026 } // namespace mutils
std::enable_if_t< std::is_base_of< ByteRepresentable CMA T >::value, std::unique_ptr< T > > from_bytes(DeserializationManager *ctx, char const *v)
Calls T::from_bytes(ctx,v) when T is a ByteRepresentable.
std::size_t from_bytes_noalloc_v(DeserializationManager *, char const *const)
void post_object_helper(const std::function< void(char const *const, std::size_t)> &f, const T &... t)
DeserializationManager(RemoteDeserialization_v rv)
bool registered() const
checks to see if a context of type T has been registered with this DeserializationManager.
std::enable_if_t< std::is_base_of< ByteRepresentable CMA std::decay_t< T > >::value, context_ptr< T > > from_bytes_noalloc(DeserializationManager *ctx, const char *v, context_ptr< std::decay_t< T >>=context_ptr< std::decay_t< T >>{})
Calls T::from_bytes_noalloc(ctx,v) when T is a ByteRepresentable.
std::size_t from_bytes_v(DeserializationManager *, char const *const)
std::size_t bytes_size() const
the size of the marshalled representation of this object.
STL namespace.
std::size_t to_bytes_v(char *)
For Serializing and Deserializing many objects at once.
virtual void post_object(const std::function< void(char const *const, std::size_t)> &) const =0
Pass a pointer to a buffer containing this class&#39;s marshalled representation into the function f...
A non-POD type which wishes to mark itself byte representable should extend this class.
virtual std::size_t to_bytes(char *v) const =0
Write this class&#39;s marshalled representation into the array found at v.
virtual std::size_t bytes_size() const =0
the size of the marshalled representation of this object.
std::unique_ptr< T, ContextDeleter< T > > context_ptr
Definition: context_ptr.hpp:20
std::chrono::nanoseconds to_exit
The manager for any RemoteDeserializationContexts.
T & mgr()
Lookup the context registered at this DeserializationManager whose type is T.
context_ptr< type_check< is_map, T > > from_bytes_noalloc(DeserializationManager *ctx, char const *v, context_ptr< T >=context_ptr< T >{})
RemoteDeserialization_v registered_v
Various registered managers.
std::unique_ptr< type_check< std::is_integral, T > > from_string(DeserializationManager *, char const *v, std::size_t length)
std::size_t from_bytes_noalloc_v_nc(DeserializationManager *dsm, char *buf, context_ptr< T > &first, context_ptr< Rest > &... rest)
std::chrono::high_resolution_clock::time_point start_time
Definition: Bytes.hpp:5
auto from_bytes_helper(DeserializationManager *ctx, char const *v)
const T & mgr() const
As the above, but const.
std::unique_ptr< T > boolvec_from_bytes(DeserializationManager *ctx, char const *v)
marshalled(decltype(size) size, decltype(data) data)
DeserializationManager(DeserializationManager &&o)
auto deserialize_and_run(DeserializationManager *dsm, char *v, const F &fun)
Calls mutils::from_bytes_noalloc<T>(ctx,v), dereferences the result, and passes it to fun...
The "marshalled" type is a wrapper for already-serialized types;.
std::vector< RemoteDeserializationContext_p > RemoteDeserialization_v
std::size_t to_bytes(char *v) const
Write this class&#39;s marshalled representation into the array found at v.
std::chrono::nanoseconds to_callfunc
std::enable_if_t< is_map< T >::value, std::unique_ptr< T > > from_bytes(DeserializationManager *ctx, char const *buffer)
static std::unique_ptr< marshalled > from_bytes(DSM const *const, char const *const)
std::size_t bytes_size_helper(const T &... t)
Sums the size of each element of the tuple.
std::function< void(char const *const, std::size_t)> post_to_buffer(std::size_t &index, char *dest_buf)
Serialization is also implemented for the following STL types: vector pair string set...
If a class which implements ByteRepresentable requires a context in order to correctly deserialize...
DeserializationManager & register_ctx(RemoteDeserializationContext_p ctx)