1010#include < cstddef>
1111#include < cstring>
1212#include < iterator>
13+ #include < ranges>
1314#include < span>
1415#include < string>
1516#include < type_traits>
@@ -156,11 +157,19 @@ namespace msgpack23 {
156157 constexpr counting_inserter operator ++(int ) {
157158 return *this ;
158159 }
160+
159161 private:
160162 std::size_t *size_{};
161163 };
162164
163- template <std::output_iterator<std::byte> Iter>
165+ template <typename T>
166+ concept byte_type = std::same_as<T, std::byte>
167+ or std::same_as<T, char >
168+ or std::same_as<T, unsigned char >
169+ or std::same_as<T, std::uint8_t >
170+ or std::same_as<T, std::int8_t >;
171+
172+ template <byte_type B, std::output_iterator<B> Iter>
164173 class Packer final {
165174 public:
166175 template <typename ... Types>
@@ -175,13 +184,13 @@ namespace msgpack23 {
175184 Iter store_;
176185
177186 void emplace_constant (FormatConstants const &value) {
178- *store_++ = static_cast <std::byte >(std::to_underlying (value));
187+ *store_++ = static_cast <B >(std::to_underlying (value));
179188 }
180189
181190 template <std::integral T>
182191 void emplace_integral (T const &value) {
183192 auto const serialize_value = to_big_endian (value);
184- auto const bytes = std::bit_cast<std::array<std::byte , sizeof (serialize_value)> >(serialize_value);
193+ auto const bytes = std::bit_cast<std::array<B , sizeof (serialize_value)> >(serialize_value);
185194 std::copy (bytes.begin (), bytes.end (), store_);
186195 }
187196
@@ -193,8 +202,8 @@ namespace msgpack23 {
193202
194203 [[nodiscard]] bool pack_map_header (std::size_t const n) {
195204 if (n < 16 ) {
196- constexpr auto size_mask = static_cast <std::byte >(0b10000000 );
197- *store_++ = static_cast <std::byte >(n) | size_mask;
205+ constexpr auto size_mask = static_cast <B >(0b10000000 );
206+ *store_++ = static_cast <B >(n) | size_mask;
198207 } else if (n < std::numeric_limits<std::uint16_t >::max ()) {
199208 emplace_combined (FormatConstants::map16, static_cast <std::uint16_t >(n));
200209 } else if (n < std::numeric_limits<std::uint32_t >::max ()) {
@@ -207,8 +216,8 @@ namespace msgpack23 {
207216
208217 [[nodiscard]] bool pack_array_header (std::size_t const n) {
209218 if (n < 16 ) {
210- constexpr auto size_mask = static_cast <std::byte >(0b10010000 );
211- *store_++ = static_cast <std::byte >(n) | size_mask;
219+ constexpr auto size_mask = static_cast <B >(0b10010000 );
220+ *store_++ = static_cast <B >(n) | size_mask;
212221 } else if (n < std::numeric_limits<std::uint16_t >::max ()) {
213222 emplace_combined (FormatConstants::array16, static_cast <std::uint16_t >(n));
214223 } else if (n < std::numeric_limits<std::uint32_t >::max ()) {
@@ -252,8 +261,8 @@ namespace msgpack23 {
252261 void pack_type (T const &value) {
253262 std::size_t size = 0 ;
254263 std::visit ([this , &size](auto const &arg) {
255- const auto inserter = counting_inserter<std::byte >{size};
256- Packer<counting_inserter<std::byte > > packer{inserter};
264+ const auto inserter = counting_inserter<B >{size};
265+ Packer<B, counting_inserter<B > > packer{inserter};
257266 packer (arg);
258267 }, value);
259268
@@ -345,7 +354,7 @@ namespace msgpack23 {
345354 if (value > 31 or value < -32 ) {
346355 emplace_constant (FormatConstants::int8);
347356 }
348- *store_++ = static_cast <std::byte >(value);
357+ *store_++ = static_cast <B >(value);
349358 }
350359
351360 void pack_type (std::int16_t const &value) {
@@ -383,10 +392,10 @@ namespace msgpack23 {
383392
384393 void pack_type (std::uint8_t const &value) {
385394 if (value < 0x80 ) {
386- *store_++ = static_cast <std::byte >(value);
395+ *store_++ = static_cast <B >(value);
387396 } else {
388397 emplace_constant (FormatConstants::uint8);
389- *store_++ = static_cast <std::byte >(value);
398+ *store_++ = static_cast <B >(value);
390399 }
391400 }
392401
@@ -437,10 +446,10 @@ namespace msgpack23 {
437446
438447 void pack_type (std::string const &value) {
439448 if (value.size () < 32 ) {
440- *store_++ = static_cast <std::byte >(value.size ()) | static_cast <std::byte >(0b10100000 );
449+ *store_++ = static_cast <B >(value.size ()) | static_cast <B >(0b10100000 );
441450 } else if (value.size () < std::numeric_limits<std::uint8_t >::max ()) {
442451 emplace_constant (FormatConstants::str8);
443- *store_++ = static_cast <std::byte >(value.size ());
452+ *store_++ = static_cast <B >(value.size ());
444453 } else if (value.size () < std::numeric_limits<std::uint16_t >::max ()) {
445454 emplace_combined (FormatConstants::str16, static_cast <std::uint16_t >(value.size ()));
446455 } else if (value.size () < std::numeric_limits<std::uint32_t >::max ()) {
@@ -449,38 +458,44 @@ namespace msgpack23 {
449458 throw std::length_error (" String is too long to be serialized." );
450459 }
451460
452- std::copy (reinterpret_cast <std::byte const * const >(value.data ()),
453- reinterpret_cast <std::byte const * const >(value.data () + value.size ()), store_);
461+ std::copy (reinterpret_cast <B const * const >(value.data ()),
462+ reinterpret_cast <B const * const >(value.data () + value.size ()), store_);
454463 }
455464
456- void pack_type (std::vector<std::byte > const &value) {
465+ void pack_type (std::vector<B > const &value) {
457466 if (value.size () < std::numeric_limits<std::uint8_t >::max ()) {
458467 emplace_constant (FormatConstants::bin8);
459- *store_++ = static_cast <std::byte >(value.size ());
468+ *store_++ = static_cast <B >(value.size ());
460469 } else if (value.size () < std::numeric_limits<std::uint16_t >::max ()) {
461470 emplace_combined (FormatConstants::bin16, static_cast <std::uint16_t >(value.size ()));
462471 } else if (value.size () < std::numeric_limits<std::uint32_t >::max ()) {
463472 emplace_combined (FormatConstants::bin32, static_cast <std::uint32_t >(value.size ()));
464473 } else {
465474 throw std::length_error (" Vector is too long to be serialized." );
466475 }
467- std::copy (reinterpret_cast <std::byte const * const >(value.data ()),
468- reinterpret_cast <std::byte const * const >(value.data () + value.size ()), store_);
476+ std::copy (reinterpret_cast <B const * const >(value.data ()),
477+ reinterpret_cast <B const * const >(value.data () + value.size ()), store_);
469478 }
470479 };
471480
481+ template <typename Container>
482+ requires byte_type<typename Container::value_type>
483+ Packer (std::back_insert_iterator<Container>) ->
484+ Packer<typename Container::value_type, std::back_insert_iterator<Container> >;
485+
472486 template <typename T, typename P>
473- concept PackableObject = requires (T t, P p)
487+ concept packable_object = requires (T t, P p)
474488 {
475489 { t.pack (p) };
476490 };
477491
492+ template <byte_type B>
478493 class Unpacker final {
479494 public:
480495 Unpacker () : data_() {
481496 }
482497
483- explicit Unpacker (std::span<std::byte const > const data) : data_(data) {
498+ explicit Unpacker (std::span<B const > const data) : data_(data) {
484499 }
485500
486501 template <typename ... Types>
@@ -489,12 +504,12 @@ namespace msgpack23 {
489504 }
490505
491506 private:
492- std::span<std::byte const > data_;
507+ std::span<B const > data_;
493508 std::size_t position_{0 };
494509
495510 [[nodiscard]] std::byte current () const {
496511 if (position_ < data_.size ()) {
497- return data_[position_];
512+ return static_cast <std::byte>( data_[position_]) ;
498513 }
499514 throw std::out_of_range (" Unpacker doesn't have enough data." );
500515 }
@@ -514,7 +529,7 @@ namespace msgpack23 {
514529 return static_cast <FormatConstants>(std::to_integer<std::uint8_t >(current ()));
515530 }
516531
517- template <typename T, std::enable_if_t <std::is_unsigned_v<T>, int > = 0 >
532+ template <typename T, std::enable_if_t <std::is_unsigned_v<T>, int > = 0 >
518533 [[nodiscard]] T read_integral () {
519534 if (position_ + sizeof (T) > data_.size ()) {
520535 throw std::out_of_range (" Unpacker doesn't have enough data." );
@@ -976,7 +991,7 @@ namespace msgpack23 {
976991 increment (str_size);
977992 }
978993
979- void unpack_type (std::vector<std::byte > &value) {
994+ void unpack_type (std::vector<B > &value) {
980995 std::size_t bin_size = 0 ;
981996 if (read_conditional<FormatConstants::bin32, std::uint32_t >(bin_size)
982997 or read_conditional<FormatConstants::bin16, std::uint16_t >(bin_size)
@@ -987,29 +1002,58 @@ namespace msgpack23 {
9871002 if (position_ + bin_size > data_.size ()) {
9881003 throw std::out_of_range (" Vector position is out of range" );
9891004 }
990- auto const *src = reinterpret_cast <std::byte const *>( data_.data () + position_) ;
1005+ auto const *src = data_.data () + position_;
9911006 value.assign (src, src + bin_size);
9921007 increment (bin_size);
9931008 }
9941009 };
9951010
9961011 template <typename T>
997- concept UnpackableObject = requires (T t, Unpacker u)
1012+ Unpacker (std::span<T const >) -> Unpacker<std::remove_const_t <T> >;
1013+
1014+ template <typename T>
1015+ concept container = requires (T b) {
1016+ typename T::value_type;
1017+ } && byte_type<typename T::value_type>;
1018+
1019+ template <container Container>
1020+ Unpacker (Container const &) -> Unpacker<typename Container::value_type>;
1021+
1022+ template <typename T, typename U>
1023+ concept unpackable_object = requires (T t, U u)
9981024 {
9991025 t.unpack (u);
10001026 };
10011027
1002- template <std::output_iterator<std::byte > Iter, PackableObject <Packer<Iter> > PackableObject>
1028+ template <byte_type B, std::output_iterator<B > Iter, packable_object <Packer<B, Iter> > PackableObject>
10031029 void pack (Iter iterator, PackableObject const &obj) {
1004- Packer<Iter> packer{iterator};
1030+ Packer<B, Iter> packer{iterator};
10051031 return obj.pack (packer);
10061032 }
10071033
1008- template <UnpackableObject UnpackableObject>
1009- [[nodiscard]] UnpackableObject unpack (std::span<const std::byte> const data) {
1034+ template <container Container, packable_object<Packer<typename Container::value_type, std::back_insert_iterator<Container>>> PackableObject>
1035+ void pack (std::back_insert_iterator<Container> iterator, PackableObject const &obj) {
1036+ return pack<typename Container::value_type, std::back_insert_iterator<Container>, PackableObject>(iterator, obj);
1037+ }
1038+
1039+ template <typename UnpackableObject, byte_type B>
1040+ requires unpackable_object<UnpackableObject, Unpacker<B>>
1041+ [[nodiscard]] UnpackableObject unpack (std::span<B const > const data) {
10101042 Unpacker unpacker (data);
10111043 UnpackableObject obj{};
10121044 obj.unpack (unpacker);
10131045 return obj;
10141046 }
1047+
1048+ template <typename T>
1049+ concept span_convertible = std::ranges::contiguous_range<T>
1050+ && std::ranges::sized_range<T>
1051+ && byte_type<std::remove_const_t <std::ranges::range_value_t <T>>>;
1052+
1053+ template <typename UnpackableObject, span_convertible Container>
1054+ requires unpackable_object<UnpackableObject, Unpacker<std::remove_const_t <std::ranges::range_value_t <Container>>>>
1055+ [[nodiscard]] UnpackableObject unpack (Container const & data) {
1056+ using B = std::remove_const_t <std::ranges::range_value_t <Container>>;
1057+ return unpack<UnpackableObject>(std::span<B const >{data});
1058+ }
10151059}
0 commit comments