Skip to content

Commit 236b854

Browse files
author
pfeatherstone
committed
- Added support for custom structs using Boost.Describe
- Added "sinks"
1 parent fc71a43 commit 236b854

File tree

5 files changed

+202
-73
lines changed

5 files changed

+202
-73
lines changed

CMakeLists.txt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,29 @@ project(Msgpack)
55
include(FetchContent)
66
include(ExternalProject)
77

8-
# set(MSGPACK_NO_BOOST ON)
8+
set(BOOST_INCLUDE_LIBRARIES describe)
9+
set(BOOST_ENABLE_CMAKE ON)
10+
FetchContent_Declare(
11+
Boost
12+
URL "https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-cmake.tar.xz"
13+
URL_HASH MD5=d02759931cedc02aded80402906c5eb6
14+
DOWNLOAD_EXTRACT_TIMESTAMP true
15+
)
16+
917
set(MSGPACK_USE_BOOST OFF CACHE INTERNAL "Disabling boost in msgpack library")
1018
FetchContent_Declare(
1119
msgpack
1220
GIT_REPOSITORY https://github.com/msgpack/msgpack-c.git
1321
GIT_TAG cpp_master
1422
)
23+
1524
FetchContent_Declare(
1625
doctest
1726
GIT_REPOSITORY https://github.com/doctest/doctest.git
1827
GIT_TAG v2.4.11
1928
)
20-
FetchContent_MakeAvailable(msgpack doctest)
29+
30+
FetchContent_MakeAvailable(Boost msgpack doctest)
2131

2232
# Unit test
2333
add_executable(Test test.cpp)

msgpack.h

Lines changed: 108 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <type_traits>
77
#include <string_view>
88
#include <vector>
9+
#include <map>
10+
#include <unordered_map>
911
#include <endian.h>
1012

1113
namespace msgpackcpp
@@ -35,35 +37,67 @@ namespace msgpackcpp
3537
}
3638

3739
template<class Stream>
38-
inline void serialize(Stream&& out, int8_t v)
40+
inline void serialize(Stream&& out, uint16_t v)
3941
{
40-
if (v < -(1<<5))
42+
if (v <= std::numeric_limits<uint8_t>::max())
4143
{
42-
// signed 8
43-
constexpr uint8_t format = 0xd0;
44+
serialize(std::forward<Stream>(out), (uint8_t)v);
45+
}
46+
else
47+
{
48+
constexpr uint8_t format = 0xcd;
49+
v = htobe16(v);
4450
out((const char*)&format, 1);
45-
out((const char*)&v, 1);
51+
out((const char*)&v, 2);
52+
}
53+
}
54+
55+
template<class Stream>
56+
inline void serialize(Stream&& out, uint32_t v)
57+
{
58+
if (v <= std::numeric_limits<uint16_t>::max())
59+
{
60+
serialize(std::forward<Stream>(out), (uint16_t)v);
4661
}
4762
else
4863
{
49-
// negative fixing (5-bit negative integer)
50-
out((const char*)&v, 1);
64+
constexpr uint8_t format = 0xce;
65+
out((const char*)&format, 1);
66+
v = htobe32(v);
67+
out((const char*)&v, 4);
5168
}
5269
}
5370

5471
template<class Stream>
55-
inline void serialize(Stream&& out, uint16_t v)
72+
inline void serialize(Stream&& out, uint64_t v)
5673
{
57-
if (v <= std::numeric_limits<uint8_t>::max())
74+
if (v <= std::numeric_limits<uint32_t>::max())
5875
{
59-
serialize(std::forward<Stream>(out), (uint8_t)v);
76+
serialize(std::forward<Stream>(out), (uint32_t)v);
6077
}
6178
else
6279
{
63-
constexpr uint8_t format = 0xcd;;
80+
constexpr uint8_t format = 0xcf;
6481
out((const char*)&format, 1);
65-
v = htobe16(v);
66-
out((const char*)&v, 2);
82+
v = htobe64(v);
83+
out((const char*)&v, 8);
84+
}
85+
}
86+
87+
template<class Stream>
88+
inline void serialize(Stream&& out, int8_t v)
89+
{
90+
if (v < -(1<<5))
91+
{
92+
// signed 8
93+
constexpr uint8_t format = 0xd0;
94+
out((const char*)&format, 1);
95+
out((const char*)&v, 1);
96+
}
97+
else
98+
{
99+
// negative fixing (5-bit negative integer)
100+
out((const char*)&v, 1);
67101
}
68102
}
69103

@@ -94,22 +128,6 @@ namespace msgpackcpp
94128
}
95129
}
96130

97-
template<class Stream>
98-
inline void serialize(Stream&& out, uint32_t v)
99-
{
100-
if (v <= std::numeric_limits<uint16_t>::max())
101-
{
102-
serialize(std::forward<Stream>(out), (uint16_t)v);
103-
}
104-
else
105-
{
106-
constexpr uint8_t format = 0xce;
107-
out((const char*)&format, 1);
108-
v = htobe32(v);
109-
out((const char*)&v, 4);
110-
}
111-
}
112-
113131
template<class Stream>
114132
inline void serialize(Stream&& out, int32_t v)
115133
{
@@ -137,22 +155,6 @@ namespace msgpackcpp
137155
}
138156
}
139157

140-
template<class Stream>
141-
inline void serialize(Stream&& out, uint64_t v)
142-
{
143-
if (v <= std::numeric_limits<uint32_t>::max())
144-
{
145-
serialize(std::forward<Stream>(out), (uint32_t)v);
146-
}
147-
else
148-
{
149-
constexpr uint8_t format = 0xcf;
150-
out((const char*)&format, 1);
151-
v = htobe64(v);
152-
out((const char*)&v, 8);
153-
}
154-
}
155-
156158
template<class Stream>
157159
inline void serialize(Stream&& out, int64_t v)
158160
{
@@ -304,4 +306,65 @@ namespace msgpackcpp
304306
for (const auto& x : v)
305307
serialize(std::forward<Stream>(out), x);
306308
}
309+
310+
template<class Stream>
311+
inline void serialize_map_size(Stream&& out, uint32_t size)
312+
{
313+
if (size < 16)
314+
{
315+
const uint8_t format = 0x80 | static_cast<uint8_t>(size);
316+
out((const char*)&format, 1);
317+
}
318+
else if (size < 65536)
319+
{
320+
const uint8_t format = 0xde;
321+
const uint16_t size16 = htobe16(static_cast<uint16_t>(size));
322+
out((const char*)&format, 1);
323+
out((const char*)&size16, 2);
324+
}
325+
else
326+
{
327+
const uint8_t format = 0xdf;
328+
const uint32_t size32 = htobe32(static_cast<uint32_t>(size));
329+
out((const char*)&format, 1);
330+
out((const char*)&size32, 4);
331+
}
332+
}
333+
334+
template <
335+
class Stream,
336+
class K,
337+
class V,
338+
class Compare = std::less<K>,
339+
class Alloc = std::allocator<std::pair<const K, V>>
340+
>
341+
inline void serialize(Stream&& out, const std::map<K,V,Compare,Alloc>& map)
342+
{
343+
serialize_map_size(std::forward<Stream>(out), map.size());
344+
345+
for (const auto& [k,v] : map)
346+
{
347+
serialize(std::forward<Stream>(out), k);
348+
serialize(std::forward<Stream>(out), v);
349+
}
350+
}
351+
352+
template <
353+
class Stream,
354+
class K,
355+
class V,
356+
class Hash = std::hash<K>,
357+
class KeyEqual = std::equal_to<K>,
358+
class Alloc = std::allocator<std::pair<const K, V>>
359+
>
360+
inline void serialize(Stream&& out, const std::unordered_map<K,V,Hash,KeyEqual,Alloc>& map)
361+
{
362+
serialize_map_size(std::forward<Stream>(out), map.size());
363+
364+
for (const auto& [k,v] : map)
365+
{
366+
serialize(std::forward<Stream>(out), k);
367+
serialize(std::forward<Stream>(out), v);
368+
}
369+
}
307370
}

msgpack_describe.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#pragma once
2+
3+
#include <boost/describe/members.hpp>
4+
#include "msgpack.h"
5+
6+
namespace msgpackcpp
7+
{
8+
template <
9+
class Stream,
10+
class T,
11+
class D = boost::describe::describe_members<T, boost::describe::mod_any_access>
12+
>
13+
inline void serialize(Stream&& out, const T& obj, bool as_map = false)
14+
{
15+
if (as_map)
16+
{
17+
serialize_map_size(std::forward<Stream>(out), boost::mp11::mp_size<D>::value);
18+
19+
boost::mp11::mp_for_each<D>([&](auto D) {
20+
serialize(std::forward<Stream>(out), D.name);
21+
serialize(std::forward<Stream>(out), obj.*D.pointer)
22+
});
23+
}
24+
else
25+
{
26+
serialize_array_size(std::forward<Stream>(out), boost::mp11::mp_size<D>::value);
27+
28+
boost::mp11::mp_for_each<D>([&](auto D) {
29+
serialize(std::forward<Stream>(out), obj.*D.pointer)
30+
});
31+
}
32+
}
33+
}

msgpack_sinks.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <ostream>
5+
6+
namespace msgpackcpp
7+
{
8+
template<class Byte, class Alloc, std::enable_if_t<sizeof(Byte) == 1, bool> = true>
9+
auto sink(std::vector<Byte, Alloc>& buf)
10+
{
11+
return [&](const char* bytes, size_t nbytes) {
12+
buf.insert(end(buf), bytes, bytes + nbytes);
13+
};
14+
}
15+
16+
inline auto sink(std::ostream& out)
17+
{
18+
return [&](const char* bytes, size_t nbytes) {
19+
out.write(bytes, nbytes);
20+
};
21+
}
22+
}

test.cpp

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <msgpack.hpp>
88
#include <doctest.h>
99
#include "msgpack.h"
10+
#include "msgpack_sinks.h"
1011

1112
template<class Byte, class Allocator>
1213
struct vector_sink
@@ -88,17 +89,17 @@ TEST_SUITE("[MSGPACK]")
8889

8990
{
9091
// using custom library
91-
vector_sink sink{buf2};
92-
msgpackcpp::serialize(sink, a);
93-
msgpackcpp::serialize(sink, b);
94-
msgpackcpp::serialize(sink, c);
95-
msgpackcpp::serialize(sink, d);
96-
msgpackcpp::serialize(sink, e);
97-
msgpackcpp::serialize(sink, f);
98-
msgpackcpp::serialize(sink, g);
99-
msgpackcpp::serialize(sink, h);
100-
msgpackcpp::serialize(sink, i);
101-
msgpackcpp::serialize(sink, j);
92+
using namespace msgpackcpp;
93+
serialize(sink(buf2), a);
94+
serialize(sink(buf2), b);
95+
serialize(sink(buf2), c);
96+
serialize(sink(buf2), d);
97+
serialize(sink(buf2), e);
98+
serialize(sink(buf2), f);
99+
serialize(sink(buf2), g);
100+
serialize(sink(buf2), h);
101+
serialize(sink(buf2), i);
102+
serialize(sink(buf2), j);
102103
}
103104

104105
REQUIRE(num_errors(buf1, buf2) == 0);
@@ -176,21 +177,21 @@ TEST_SUITE("[MSGPACK]")
176177

177178
{
178179
// using custom library
179-
vector_sink sink{buf2};
180-
msgpackcpp::serialize(sink, k);
181-
msgpackcpp::serialize(sink, l);
182-
msgpackcpp::serialize(sink, m);
183-
msgpackcpp::serialize(sink, n);
184-
msgpackcpp::serialize(sink, o);
185-
msgpackcpp::serialize(sink, p);
186-
msgpackcpp::serialize(sink, q);
187-
msgpackcpp::serialize(sink, r);
188-
msgpackcpp::serialize(sink, s);
189-
msgpackcpp::serialize(sink, t);
190-
msgpackcpp::serialize(sink, u);
191-
msgpackcpp::serialize(sink, v);
192-
msgpackcpp::serialize(sink, w);
193-
msgpackcpp::serialize(sink, x);
180+
using namespace msgpackcpp;
181+
serialize(sink(buf2), k);
182+
serialize(sink(buf2), l);
183+
serialize(sink(buf2), m);
184+
serialize(sink(buf2), n);
185+
serialize(sink(buf2), o);
186+
serialize(sink(buf2), p);
187+
serialize(sink(buf2), q);
188+
serialize(sink(buf2), r);
189+
serialize(sink(buf2), s);
190+
serialize(sink(buf2), t);
191+
serialize(sink(buf2), u);
192+
serialize(sink(buf2), v);
193+
serialize(sink(buf2), w);
194+
serialize(sink(buf2), x);
194195
}
195196

196197
REQUIRE(num_errors(buf1, buf2) == 0);

0 commit comments

Comments
 (0)