19 #ifndef TIMPI_PACKING_H 20 #define TIMPI_PACKING_H 31 #include <type_traits> 37 #if __cplusplus >= 201703 38 # define timpi_if_constexpr if constexpr 40 # define timpi_if_constexpr if 59 template <
typename T,
typename Enable>
74 template <
typename OutputIter,
typename Context>
75 static void pack(
const T &
object,
77 const Context * context);
81 template <
typename Context>
83 const Context * context);
88 template <
typename BufferIter>
93 template <
typename BufferIter,
typename Context>
94 static T
unpack(BufferIter in, Context * ctx);
102 template <
typename buffer_type>
108 (
sizeof(
unsigned int) + (
sizeof(buffer_type)-1)) /
113 template <
typename buffer_type,
typename Iter>
122 constexpr
int n_bits = (
sizeof(buffer_type) * CHAR_BIT);
126 if (n_bits <
sizeof(
unsigned int) * CHAR_BIT)
128 constexpr
int size_entries = get_packed_len_entries<buffer_type>();
133 constexpr
int compiler_workaround =
134 std::max(n_bits-1,
int(
sizeof(
unsigned int) * CHAR_BIT));
136 const std::size_t max_entry = std::size_t(1) <<
139 for (
unsigned int i=0; i != size_entries; ++i)
141 *data_out++ = (len % max_entry);
149 timpi_assert_equal_to(get_packed_len_entries<buffer_type>(), 1);
154 template <
typename buffer_type>
161 constexpr
int n_bits = (
sizeof(buffer_type) * CHAR_BIT);
166 timpi_if_constexpr (n_bits <
sizeof(
unsigned int) * CHAR_BIT)
168 const int n_size_entries = get_packed_len_entries<buffer_type>();
169 unsigned int packed_len = 0;
171 for (
signed int i = n_size_entries-1; i >= 0; --i)
173 packed_len <<= n_bits;
175 const auto next_entry = in[i];
178 packed_len += 1 << n_bits;
180 packed_len += next_entry;
187 timpi_assert_equal_to(get_packed_len_entries<buffer_type>(), 1);
188 timpi_assert_greater_equal(*in, 0);
196 template <
typename ValueType>
201 template <
typename K,
typename V>
210 template <
typename BufferType>
215 template <
typename T3>
223 template <
typename T3>
229 template <
typename T3,
231 typename std::enable_if<IsFixed<T3>::value,
int>::type = 0>
238 template <
typename T1,
typename T2,
240 typename std::enable_if<IsFixed<std::pair<T1, T2>>::value,
int>::type = 0>
247 template <
typename T3,
249 typename std::enable_if<!IsFixed<T3>::value,
int>::type = 0>
259 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) 260 #pragma GCC diagnostic push 261 #pragma GCC diagnostic ignored "-Wstack-protector" 264 template <
typename T3,
267 typename std::enable_if<IsFixed<T3>::value,
int>::type = 0>
268 static void pack_comp(
const T3 & comp, OutputIter data_out,
const Context *)
271 std::memcpy(T3_as_buffer_types, &comp,
sizeof(T3));
273 *data_out++ = T3_as_buffer_types[i];
276 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) 277 #pragma GCC diagnostic pop 281 template <
typename T1,
typename T2,
284 typename std::enable_if<IsFixed<std::pair<T1, T2>>::value,
int>::type = 0>
285 static void pack_comp(
const std::pair<T1, T2> & comp, OutputIter data_out,
const Context * ctx)
291 template <
typename T3,
294 typename std::enable_if<!IsFixed<T3>::value,
int>::type = 0>
295 static void pack_comp(
const T3 & comp, OutputIter data_out,
const Context * ctx)
300 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) 301 #pragma GCC diagnostic push 302 #pragma GCC diagnostic ignored "-Wstack-protector" 305 template <
typename T3,
308 typename std::enable_if<IsFixed<T3>::value,
int>::type = 0>
322 char * comp_bytes =
reinterpret_cast<char *
>(&comp);
323 std::memcpy(comp_bytes, &(*in),
sizeof(T3));
326 #if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) 327 #pragma GCC diagnostic pop 330 template <
typename T1,
typename T2,
333 typename std::enable_if<IsFixed<std::pair<T1, T2>>::value,
int>::type = 0>
334 static void unpack_comp(std::pair<T1, T2> & comp, BufferIter in, Context * ctx)
344 template <
typename T3,
347 typename std::enable_if<!IsFixed<T3>::value,
int>::type = 0>
358 template <
typename T1,
bool T1_has_buffer_type,
typename T2,
bool T2_has_buffer_type>
361 template <
typename T1,
typename T2>
365 "For ease of use we cannot pack two types that use two different buffer types");
370 template <
typename T1,
typename T2>
376 template <
typename T1,
typename T2>
382 template <
typename T1,
typename T2>
390 template <
typename T1,
typename T2>
392 typename std::enable_if<PairHasPacking<T1,T2>::value>::type>
395 typedef typename std::remove_const<T1>::type
cT1;
403 template <
typename OutputIter,
typename Context>
404 static void pack(
const std::pair<T1, T2> & pr, OutputIter data_out,
const Context * context);
406 template <
typename Context>
407 static unsigned int packable_size(
const std::pair<T1, T2> & pr,
const Context * context);
409 template <
typename BufferIter>
412 template <
typename BufferIter,
typename Context>
413 static std::pair<T1, T2>
unpack(BufferIter in, Context * ctx);
416 template <
typename T1,
typename T2>
417 template <
typename Context>
420 typename std::enable_if<PairHasPacking<T1,T2>::value>::type>::
421 packable_size(
const std::pair<T1, T2> & pr,
const Context * ctx)
423 return get_packed_len_entries<buffer_type>() +
424 Mixed::packable_size_comp(pr.first, ctx) +
425 Mixed::packable_size_comp(pr.second, ctx);
428 template <
typename T1,
typename T2>
429 template <
typename BufferIter>
432 typename std::enable_if<PairHasPacking<T1,T2>::value>::type>::
433 packed_size(BufferIter iter)
436 return get_packed_len<buffer_type>(iter);
439 template <
typename T1,
typename T2>
440 template <
typename OutputIter,
typename Context>
443 typename std::enable_if<PairHasPacking<T1,T2>::value>::type>::
444 pack(
const std::pair<T1, T2> & pr, OutputIter data_out,
const Context * ctx)
446 unsigned int size = packable_size(pr, ctx);
449 put_packed_len<buffer_type>(size, data_out);
452 Mixed::pack_comp(pr.first, data_out, ctx);
459 Mixed::pack_comp(pr.second, data_out, ctx);
462 template <
typename T1,
typename T2>
463 template <
typename BufferIter,
typename Context>
466 typename std::enable_if<PairHasPacking<T1,T2>::value>::type>::
467 unpack(BufferIter in, Context * ctx)
469 std::pair<T1, T2> pr;
472 constexpr
int size_bytes = get_packed_len_entries<buffer_type>();
476 Mixed::unpack_comp(pr.first, in, ctx);
479 in += Mixed::packable_size_comp(pr.first, ctx);
481 Mixed::unpack_comp(pr.second, in, ctx);
489 template <
bool T1_has_buffer_type,
bool MoreTypes_have_buffer_Type,
typename T1,
typename... MoreTypes>
492 template <
typename T1,
bool MoreTypes_have_buffer_Type>
497 template <
typename T1,
typename... MoreTypes>
501 "For ease of use we cannot pack two types that use two different buffer types");
506 template <
typename T1,
typename... MoreTypes>
511 template <
typename T1,
typename... MoreTypes>
516 template <
typename... Types>
520 template <
typename T1>
527 template <
typename T1,
typename... MoreTypes>
539 template <
typename Enable>
542 template <
typename T,
typename... Types>
544 typename std::enable_if<TupleHasPacking<T, Types...>::value>::type>
551 template <
typename OutputIter,
typename Context>
552 static void pack(
const std::tuple<T, Types...> & tup, OutputIter data_out,
const Context * context);
554 template <
typename Context>
555 static unsigned int packable_size(
const std::tuple<T, Types...> & tup,
const Context * context);
557 template <
typename BufferIter>
560 template <
typename BufferIter,
typename Context>
561 static std::tuple<T, Types...>
unpack(BufferIter in, Context * ctx);
563 template <
typename Context,
565 static typename std::enable_if<I ==
sizeof...(Types)+1,
unsigned int>::type
570 template <
typename Context,
572 static typename std::enable_if<I <
sizeof...(Types)+1,
unsigned int>::type
573 tail_packable_size(
const std::tuple<T, Types...> &tup,
576 return Mixed::packable_size_comp(std::get<I>(tup), ctx) +
577 tail_packable_size<Context, I+1>(tup, ctx);
580 template <
typename Context,
583 static typename std::enable_if<I ==
sizeof...(Types)+1,
void>::type
584 tail_pack_comp(
const std::tuple<T, Types...> &,
588 template <
typename Context,
591 static typename std::enable_if<I <
sizeof...(Types)+1,
void>::type
592 tail_pack_comp(
const std::tuple<T, Types...> &tup,
596 Mixed::pack_comp(std::get<I>(tup), data_out, ctx);
597 tail_pack_comp<Context, OutputIter, I+1>(tup, data_out, ctx);
600 template <
typename Context,
603 static typename std::enable_if<I ==
sizeof...(Types)+1,
void>::type
604 tail_unpack_comp(std::tuple<T, Types...> &,
608 template <
typename Context,
611 static typename std::enable_if<I <
sizeof...(Types)+1,
void>::type
612 tail_unpack_comp(std::tuple<T, Types...> &tup,
616 Mixed::unpack_comp(std::get<I>(tup), in, ctx);
621 in += Mixed::packable_size_comp(std::get<I>(tup), ctx);
623 tail_unpack_comp<Context, BufferIter, I+1>(tup, in, ctx);
628 template <
typename T,
typename... Types>
629 template <
typename Context>
631 Packing<std::tuple<T, Types...>,
632 typename std::enable_if<TupleHasPacking<T, Types...>::value>::type>::
633 packable_size(
const std::tuple<T, Types...> & tup,
const Context * ctx)
635 return get_packed_len_entries<buffer_type>() +
636 tail_packable_size<Context, 0>(tup, ctx);
639 template <
typename T,
typename... Types>
640 template <
typename BufferIter>
642 Packing<std::tuple<T, Types...>,
644 packed_size(BufferIter iter)
647 return get_packed_len<buffer_type>(iter);
650 template <
typename T,
typename... Types>
651 template <
typename OutputIter,
typename Context>
653 Packing<std::tuple<T, Types...>,
655 pack(
const std::tuple<T, Types...> & tup, OutputIter data_out,
const Context * ctx)
657 unsigned int size = packable_size(tup, ctx);
660 put_packed_len<buffer_type>(size, data_out);
663 tail_pack_comp<Context, OutputIter, 0>(tup, data_out, ctx);
666 template <
typename T,
typename... Types>
667 template <
typename BufferIter,
typename Context>
668 std::tuple<T, Types...>
669 Packing<std::tuple<T, Types...>,
671 unpack(BufferIter in, Context * ctx)
673 std::tuple<T, Types...> tup;
676 constexpr
int size_bytes = get_packed_len_entries<buffer_type>();
680 tail_unpack_comp<Context, BufferIter, 0>(tup, in, ctx);
688 template <
typename T, std::
size_t N>
690 typename std::enable_if<Has_buffer_type<Packing<T>>::value>::type>
697 template <
typename OutputIter,
typename Context>
698 static void pack(
const std::array<T, N> & a, OutputIter data_out,
const Context * context);
700 template <
typename Context>
701 static unsigned int packable_size(
const std::array<T, N> & a,
const Context * context);
703 template <
typename BufferIter>
706 template <
typename BufferIter,
typename Context>
707 static std::array<T, N>
unpack(BufferIter in, Context * ctx);
710 template <
typename T, std::
size_t N>
711 template <
typename Context>
714 typename std::enable_if<Has_buffer_type<Packing<T>>::value>::type>::
715 packable_size(
const std::array<T, N> & a,
const Context * ctx)
717 unsigned int returnval = get_packed_len_entries<buffer_type>();
718 for (
const auto & entry : a)
719 returnval += Mixed::packable_size_comp(entry, ctx);
723 template <
typename T, std::
size_t N>
724 template <
typename BufferIter>
727 typename std::enable_if<Has_buffer_type<Packing<T>>::value>::type>::
728 packed_size(BufferIter iter)
731 return get_packed_len<buffer_type>(iter);
734 template <
typename T, std::
size_t N>
735 template <
typename OutputIter,
typename Context>
738 typename std::enable_if<Has_buffer_type<Packing<T>>::value>::type>::
739 pack(
const std::array<T, N> & a, OutputIter data_out,
const Context * ctx)
741 unsigned int size = packable_size(a, ctx);
744 put_packed_len<buffer_type>(size, data_out);
747 for (
const auto & entry : a)
748 Mixed::pack_comp(entry, data_out, ctx);
751 template <
typename T, std::
size_t N>
752 template <
typename BufferIter,
typename Context>
755 typename std::enable_if<Has_buffer_type<Packing<T>>::value>::type>::
756 unpack(BufferIter in, Context * ctx)
761 constexpr
int size_bytes = get_packed_len_entries<buffer_type>();
765 for (
auto & entry : a)
767 Mixed::unpack_comp(entry, in, ctx);
770 in += Mixed::packable_size_comp(entry, ctx);
781 template <
typename T,
typename Enable=
void>
784 template <
typename T>
790 template <
typename T>
799 template <
typename Container>
809 template <
typename OutputIter,
typename Context>
810 static void pack(
const Container & a,
811 OutputIter data_out,
const Context * context);
813 template <
typename Context>
815 const Context * context);
817 template <
typename BufferIter>
820 template <
typename BufferIter,
typename Context>
821 static Container
unpack(BufferIter in, Context * ctx);
825 template <
typename Container>
826 template <
typename Context>
830 unsigned int returnval = get_packed_len_entries<buffer_type>();
831 for (
const auto & entry : c)
832 returnval += Mixed::packable_size_comp(entry, ctx);
836 template <
typename Container>
837 template <
typename BufferIter>
842 return get_packed_len<buffer_type>(iter);
845 template <
typename Container>
846 template <
typename OutputIter,
typename Context>
850 unsigned int size = packable_size(c, ctx);
853 put_packed_len<buffer_type>(size, data_out);
856 for (
const auto & entry : c)
857 Mixed::pack_comp(entry, data_out, ctx);
860 template <
typename Container>
861 template <
typename BufferIter,
typename Context>
867 unsigned int size = packed_size(in);
869 timpi_assert_greater(size, 0);
872 constexpr
int size_bytes = get_packed_len_entries<buffer_type>();
877 std::size_t unpacked_size = 0;
878 while (unpacked_size < size)
881 Mixed::unpack_comp(entry, in, ctx);
883 c.insert(c.end(), entry);
886 const std::size_t unpacked_size_comp =
887 Mixed::packable_size_comp(entry, ctx);
888 in += unpacked_size_comp;
889 unpacked_size += unpacked_size_comp;
894 timpi_assert_equal_to(unpacked_size, size);
901 #define TIMPI_PACKING_RANGE_SUBCLASS(Container) \ 902 class Packing<Container, \ 903 typename std::enable_if<Has_buffer_type<Packing<typename Container::value_type>>::value || \ 904 TIMPI::StandardType<typename Container::value_type>::is_fixed_type>::type> : \ 905 public PackingRange<Container> \ 908 using typename PackingRange<Container>::buffer_type; \ 910 using typename PackingRange<Container>::Mixed; \ 912 using PackingRange<Container>::pack; \ 913 using PackingRange<Container>::packable_size; \ 914 using PackingRange<Container>::packed_size; \ 915 using PackingRange<Container>::unpack; \ 919 template <
typename T,
typename A>
922 template <
typename T,
typename A>
925 template <
typename K,
typename T,
typename C,
typename A>
928 template <
typename K,
typename T,
typename C,
typename A>
931 template <
typename K,
typename C,
typename A>
934 template <
typename K,
typename C,
typename A>
937 template <
typename K,
typename T,
typename H,
typename KE,
typename A>
940 template <
typename K,
typename T,
typename H,
typename KE,
typename A>
943 template <
typename K,
typename H,
typename KE,
typename A>
946 template <
typename K,
typename H,
typename KE,
typename A>
950 template <
typename T>
952 typename std::enable_if<TIMPI::StandardType<T>::is_fixed_type>::type>
959 "We don't support strings with larger characters than unsigned int");
961 static constexpr
int T_per_buffer_type = (
sizeof(
buffer_type) +
sizeof(T) - 1)/
sizeof(T);
964 packed_size (
typename std::vector<buffer_type>::const_iterator in)
967 return 1 + (*in+T_per_buffer_type-1)/T_per_buffer_type;
971 (
const std::basic_string<T> & s,
974 return 1 + (s.size()+T_per_buffer_type-1)/T_per_buffer_type;
978 template <
typename Iter>
979 static void pack (
const std::basic_string<T> & b, Iter data_out,
982 *data_out++ = b.size();
984 for (; i + T_per_buffer_type < b.size(); i += T_per_buffer_type)
985 *data_out++ = *reinterpret_cast<const buffer_type *>(&b[i]);
988 T with_padding[T_per_buffer_type] = {};
989 std::copy(b.begin()+i, b.end(), &with_padding[0]);
990 *data_out++ = *
reinterpret_cast<const buffer_type *
>(&with_padding[0]);
994 static std::basic_string<T>
995 unpack (
typename std::vector<buffer_type>::const_iterator in,
void *)
997 const unsigned int string_len = *in++;
1000 reinterpret_cast<const T *
>(&(*in));
1001 in += string_len / T_per_buffer_type;
1002 return {buf, buf+string_len};
1022 template <
typename Context,
typename Iter>
1025 const Iter range_end)
1027 typedef typename std::iterator_traits<Iter>::value_type T;
1029 std::size_t buffer_size = 0;
1030 for (Iter range_count = range_begin;
1031 range_count != range_end;
1043 template <
typename Context,
typename buffertype,
typename Iter>
1046 const Iter range_end,
1047 std::vector<buffertype> & buffer,
1052 std::size_t approx_buffer_size)
1054 typedef typename std::iterator_traits<Iter>::value_type T;
1058 std::size_t buffer_size = 0;
1059 Iter range_stop = range_begin;
1060 for (; range_stop != range_end && buffer_size < approx_buffer_size;
1063 std::size_t next_buffer_size =
1065 buffer_size += next_buffer_size;
1067 buffer.reserve(buffer.size() + buffer_size);
1070 for (; range_begin != range_stop; ++range_begin)
1073 std::size_t old_size = buffer.size();
1077 (*range_begin, std::back_inserter(buffer), context);
1080 unsigned int my_packable_size =
1082 unsigned int my_packed_size =
1084 timpi_assert_equal_to (my_packable_size, my_packed_size);
1085 timpi_assert_equal_to (buffer.size(), old_size + my_packable_size);
1101 template <
typename Context,
typename buffertype,
1102 typename OutputIter,
typename T>
1105 OutputIter out_iter,
1110 typename std::vector<buffertype>::const_iterator
1111 next_object_start = buffer.begin();
1113 while (next_object_start < buffer.end())
1116 next_object_start +=
1121 timpi_assert (next_object_start == buffer.end());
1128 #endif // TIMPI_PACKING_H std::remove_const< T1 >::type cT1
static void pack(const std::basic_string< T > &b, Iter data_out, const void *)
OutputIter unpack_range(const std::vector< buffertype > &buffer, Context *context, OutputIter out_iter, const T *)
Helper function for range unpacking.
void put_packed_len(unsigned int len, Iter data_out)
Packing< T1 >::buffer_type buffer_type
static unsigned int packable_size(const Container &a, const Context *context)
static std::basic_string< T > unpack(typename std::vector< buffer_type >::const_iterator in, void *)
static Container unpack(BufferIter in, Context *ctx)
static void pack_comp(const std::pair< T1, T2 > &comp, OutputIter data_out, const Context *ctx)
Templated class to provide the appropriate MPI datatype for use with built-in C types or simple C++ c...
static unsigned int packed_size(typename std::vector< buffer_type >::const_iterator in)
static void pack_comp(const T3 &comp, OutputIter data_out, const Context *ctx)
Define data types and (un)serialization functions for use when encoding a potentially-variable-size o...
static T unpack(BufferIter in, Context *ctx)
static unsigned int packable_size(const T &object, const Context *context)
unsigned int get_packed_len(typename std::vector< buffer_type >::const_iterator in)
Packing< T1 >::buffer_type buffer_type
Packing< T2 >::buffer_type buffer_type
static std::enable_if< I==sizeof...(Types)+1, unsigned int >::type tail_packable_size(const std::tuple< T, Types... > &, const Context *)
Packing< std::tuple< MoreTypes... > >::buffer_type buffer_type
static unsigned int packable_size_comp(const std::pair< T1, T2 > &comp, const Context *ctx)
static unsigned int packed_size(BufferIter iter)
static unsigned int packed_size(BufferIter iter)
static void pack(const Container &a, OutputIter data_out, const Context *context)
Iter pack_range(const Context *context, Iter range_begin, const Iter range_end, std::vector< buffertype > &buffer, std::size_t approx_buffer_size)
Helper function for range packing.
PackingMixedType< buffer_type > Mixed
Packing< T >::buffer_type type
static void pack(const T &object, OutputIter data_out, const Context *context)
PackingMixedType< buffer_type > Mixed
Packing< T >::buffer_type buffer_type
Packing< T1 >::buffer_type buffer_type
constexpr int get_packed_len_entries()
static void unpack_comp(std::pair< T1, T2 > &comp, BufferIter in, Context *ctx)
Packing< T1 >::buffer_type buffer_type
Packing< T1 >::buffer_type buffer_type
TupleBufferTypeHelper< Has_buffer_type< Packing< T1 > >::value, Has_buffer_type< Packing< std::tuple< MoreTypes... > > >::value, T1, MoreTypes... >::buffer_type buffer_type
static void unpack_comp(T3 &comp, BufferIter in, Context *ctx)
static void unpack_comp(T3 &comp, BufferIter in, Context *)
PackingMixedType< buffer_type > Mixed
static void pack_comp(const T3 &comp, OutputIter data_out, const Context *)
PairBufferTypeHelper< cT1, Has_buffer_type< Packing< cT1 > >::value, T2, Has_buffer_type< Packing< T2 > >::value >::buffer_type buffer_type
static unsigned int packable_size_comp(const T3 &, const Context *)
PackingMixedType< buffer_type > Mixed
Packing< T1 >::buffer_type buffer_type
static unsigned int packable_size_comp(const T3 &comp, const Context *ctx)
static const unsigned int value
std::size_t packed_range_size(const Context *context, Iter range_begin, const Iter range_end)
Helper function for range packing.
TupleBufferType< T, Types... >::buffer_type buffer_type
TIMPI_PACKING_RANGE_SUBCLASS(std::vector< T TIMPI_P_COMMA A >)
DefaultBufferType< typename Container::value_type >::type buffer_type