Skip to content

Commit ff14be8

Browse files
committed
Added EXT type supporting classes.
1 parent 1790062 commit ff14be8

File tree

7 files changed

+386
-1
lines changed

7 files changed

+386
-1
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ IF (MSGPACK_ENABLE_CXX)
121121
include/msgpack/adaptor/detail/cpp03_msgpack_tuple.hpp
122122
include/msgpack/adaptor/detail/cpp11_define.hpp
123123
include/msgpack/adaptor/detail/cpp11_msgpack_tuple.hpp
124+
include/msgpack/adaptor/ext.hpp
124125
include/msgpack/adaptor/fixint.hpp
125126
include/msgpack/adaptor/float.hpp
126127
include/msgpack/adaptor/int.hpp

include/msgpack/adaptor/check_container_size.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ template <>
4747
inline void check_container_size<4>(std::size_t /*size*/) {
4848
}
4949

50+
template <std::size_t N>
51+
inline void check_container_size_for_ext(std::size_t size) {
52+
if (size > 0xffffffff) throw container_size_overflow("container size overflow");
53+
}
54+
55+
template <>
56+
inline void check_container_size_for_ext<4>(std::size_t size) {
57+
if (size > 0xfffffffe) throw container_size_overflow("container size overflow");
58+
}
59+
5060
} // namespace detail
5161

5262
template <typename T>

include/msgpack/adaptor/ext.hpp

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
//
2+
// MessagePack for C++ static resolution routine
3+
//
4+
// Copyright (C) 2015 KONDO Takatoshi
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
#ifndef MSGPACK_TYPE_EXT_HPP
19+
#define MSGPACK_TYPE_EXT_HPP
20+
21+
#include "msgpack/versioning.hpp"
22+
#include "msgpack/adaptor/adaptor_base.hpp"
23+
#include <cstring>
24+
#include <string>
25+
#include <cassert>
26+
27+
namespace msgpack {
28+
29+
/// @cond
30+
MSGPACK_API_VERSION_NAMESPACE(v1) {
31+
/// @endcond
32+
33+
namespace type {
34+
class ext_ref;
35+
36+
class ext {
37+
public:
38+
ext() : m_data(1, 0) {}
39+
ext(int8_t t, const char* p, uint32_t s) {
40+
detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
41+
m_data.reserve(static_cast<std::size_t>(s) + 1);
42+
m_data.push_back(static_cast<char>(t));
43+
m_data.insert(m_data.end(), p, p + s);
44+
}
45+
ext(int8_t t, uint32_t s) {
46+
detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
47+
m_data.resize(static_cast<std::size_t>(s) + 1);
48+
m_data[0] = static_cast<char>(t);
49+
}
50+
ext(ext_ref const&);
51+
int8_t type() const {
52+
return static_cast<int8_t>(m_data[0]);
53+
}
54+
const char* data() const {
55+
return &m_data[1];
56+
}
57+
char* data() {
58+
return &m_data[1];
59+
}
60+
uint32_t size() const {
61+
return m_data.size() - 1;
62+
}
63+
bool operator== (const ext& x) const {
64+
return m_data == x.m_data;
65+
}
66+
67+
bool operator!= (const ext& x) const {
68+
return !(*this == x);
69+
}
70+
71+
bool operator< (const ext& x) const {
72+
return m_data < x.m_data;
73+
}
74+
75+
bool operator> (const ext& x) const {
76+
return m_data > x.m_data;
77+
}
78+
private:
79+
std::vector<char> m_data;
80+
friend class ext_ref;
81+
};
82+
83+
} // namespace type
84+
85+
namespace adaptor {
86+
87+
template <>
88+
struct convert<msgpack::type::ext> {
89+
msgpack::object const& operator()(msgpack::object const& o, msgpack::type::ext& v) const {
90+
if(o.type != msgpack::type::EXT) {
91+
throw msgpack::type_error();
92+
}
93+
v = msgpack::type::ext(o.via.ext.type(), o.via.ext.data(), o.via.ext.size);
94+
return o;
95+
}
96+
};
97+
98+
template <>
99+
struct pack<msgpack::type::ext> {
100+
template <typename Stream>
101+
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const msgpack::type::ext& v) const {
102+
// size limit has aleady been checked at ext's constructor
103+
uint32_t size = v.size();
104+
o.pack_ext(size, v.type());
105+
o.pack_ext_body(v.data(), size);
106+
return o;
107+
}
108+
};
109+
110+
template <>
111+
struct object_with_zone<msgpack::type::ext> {
112+
void operator()(msgpack::object::with_zone& o, const msgpack::type::ext& v) const {
113+
// size limit has aleady been checked at ext's constructor
114+
uint32_t size = v.size();
115+
o.type = msgpack::type::EXT;
116+
char* ptr = static_cast<char*>(o.zone.allocate_align(size + 1));
117+
o.via.ext.ptr = ptr;
118+
o.via.ext.size = size;
119+
ptr[0] = static_cast<char>(v.type());
120+
std::memcpy(ptr + 1, v.data(), size);
121+
}
122+
};
123+
124+
} // namespace adaptor
125+
126+
namespace type {
127+
128+
class ext_ref {
129+
public:
130+
// ext_ref should be default constructible to support 'convert'.
131+
// A default constructed ext_ref object::m_ptr doesn't have the buffer to point to.
132+
// In order to avoid nullptr checking branches, m_ptr points to m_size.
133+
// So type() returns unspecified but valid value. It might be a zero because m_size
134+
// is initialized as zero, but shoudn't assume that.
135+
ext_ref() : m_ptr(static_cast<char*>(static_cast<void*>(&m_size))), m_size(0) {}
136+
ext_ref(const char* p, uint32_t s) :
137+
m_ptr(s == 0 ? static_cast<char*>(static_cast<void*>(&m_size)) : p),
138+
m_size(s == 0 ? 0 : s - 1) {
139+
detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
140+
}
141+
142+
// size limit has aleady been checked at ext's constructor
143+
ext_ref(ext const& x) : m_ptr(&x.m_data[0]), m_size(x.size()) {}
144+
145+
const char* data() const {
146+
return m_ptr + 1;
147+
}
148+
149+
uint32_t size() const {
150+
return m_size;
151+
}
152+
153+
int8_t type() const {
154+
return static_cast<int8_t>(m_ptr[0]);
155+
}
156+
157+
std::string str() const {
158+
return std::string(m_ptr + 1, m_size);
159+
}
160+
161+
bool operator== (const ext_ref& x) const {
162+
return m_size == x.m_size && std::memcmp(m_ptr, x.m_ptr, m_size) == 0;
163+
}
164+
165+
bool operator!= (const ext_ref& x) const {
166+
return !(*this == x);
167+
}
168+
169+
bool operator< (const ext_ref& x) const {
170+
if (m_size < x.m_size) return true;
171+
if (m_size > x.m_size) return false;
172+
return std::memcmp(m_ptr, x.m_ptr, m_size) < 0;
173+
}
174+
175+
bool operator> (const ext_ref& x) const {
176+
if (m_size > x.m_size) return true;
177+
if (m_size < x.m_size) return false;
178+
return std::memcmp(m_ptr, x.m_ptr, m_size) > 0;
179+
}
180+
private:
181+
const char* m_ptr;
182+
uint32_t m_size;
183+
friend struct msgpack::adaptor::object<msgpack::type::ext_ref>;
184+
};
185+
186+
ext::ext(ext_ref const& x) {
187+
// size limit has aleady been checked at ext_ref's constructor
188+
m_data.reserve(x.size() + 1);
189+
190+
m_data.push_back(x.type());
191+
m_data.insert(m_data.end(), x.data(), x.data() + x.size());
192+
}
193+
194+
} // namespace type
195+
196+
namespace adaptor {
197+
198+
template <>
199+
struct convert<msgpack::type::ext_ref> {
200+
msgpack::object const& operator()(msgpack::object const& o, msgpack::type::ext_ref& v) const {
201+
if(o.type != msgpack::type::EXT) { throw msgpack::type_error(); }
202+
v = msgpack::type::ext_ref(o.via.ext.ptr, o.via.ext.size + 1);
203+
return o;
204+
}
205+
};
206+
207+
template <>
208+
struct pack<msgpack::type::ext_ref> {
209+
template <typename Stream>
210+
msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const msgpack::type::ext_ref& v) const {
211+
// size limit has aleady been checked at ext_ref's constructor
212+
uint32_t size = v.size();
213+
o.pack_ext(size, v.type());
214+
o.pack_ext_body(v.data(), size);
215+
return o;
216+
}
217+
};
218+
219+
template <>
220+
struct object<msgpack::type::ext_ref> {
221+
void operator()(msgpack::object& o, const msgpack::type::ext_ref& v) const {
222+
// size limit has aleady been checked at ext_ref's constructor
223+
uint32_t size = v.size();
224+
o.type = msgpack::type::EXT;
225+
o.via.ext.ptr = v.m_ptr;
226+
o.via.ext.size = size;
227+
}
228+
};
229+
230+
template <>
231+
struct object_with_zone<msgpack::type::ext_ref> {
232+
void operator()(msgpack::object::with_zone& o, const msgpack::type::ext_ref& v) const {
233+
static_cast<msgpack::object&>(o) << v;
234+
}
235+
};
236+
237+
} // namespace adaptor
238+
239+
/// @cond
240+
} // MSGPACK_API_VERSION_NAMESPACE(v1)
241+
/// @endcond
242+
243+
} // namespace msgpack
244+
245+
#endif // MSGPACK_TYPE_EXT_HPP

include/msgpack/type.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "adaptor/bool.hpp"
33
#include "adaptor/char_ptr.hpp"
44
#include "adaptor/deque.hpp"
5+
#include "adaptor/ext.hpp"
56
#include "adaptor/fixint.hpp"
67
#include "adaptor/float.hpp"
78
#include "adaptor/int.hpp"

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ nobase_include_HEADERS += \
7272
../include/msgpack/adaptor/detail/cpp03_msgpack_tuple.hpp \
7373
../include/msgpack/adaptor/detail/cpp11_define.hpp \
7474
../include/msgpack/adaptor/detail/cpp11_msgpack_tuple.hpp \
75+
../include/msgpack/adaptor/ext.hpp \
7576
../include/msgpack/adaptor/fixint.hpp \
7677
../include/msgpack/adaptor/float.hpp \
7778
../include/msgpack/adaptor/int.hpp \

test/msgpack_basic.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ TEST(MSGPACK, simple_buffer_fixext_4byte_65536)
452452
msgpack::sbuffer sbuf;
453453
msgpack::packer<msgpack::sbuffer> packer(sbuf);
454454
char buf[size];
455-
for (int i = 0; i != size; ++i) buf[i] = static_cast<char>(i);
455+
for (std::size_t i = 0; i != size; ++i) buf[i] = static_cast<char>(i);
456456
packer.pack_ext(sizeof(buf), 77);
457457
packer.pack_ext_body(buf, sizeof(buf));
458458

@@ -464,6 +464,85 @@ TEST(MSGPACK, simple_buffer_fixext_4byte_65536)
464464
std::equal(buf, buf + sizeof(buf), ret.get().via.ext.data()));
465465
}
466466

467+
TEST(MSGPACK, simple_buffer_ext_convert)
468+
{
469+
std::size_t const size = 65536;
470+
msgpack::sbuffer sbuf;
471+
msgpack::packer<msgpack::sbuffer> packer(sbuf);
472+
char buf[size];
473+
for (std::size_t i = 0; i != size; ++i) buf[i] = static_cast<char>(i);
474+
packer.pack_ext(sizeof(buf), 77);
475+
packer.pack_ext_body(buf, sizeof(buf));
476+
477+
msgpack::unpacked ret;
478+
msgpack::unpack(ret, sbuf.data(), sbuf.size());
479+
msgpack::type::ext e;
480+
ret.get().convert(e);
481+
EXPECT_EQ(size, e.size());
482+
EXPECT_EQ(77, e.type());
483+
EXPECT_TRUE(
484+
std::equal(buf, buf + sizeof(buf), e.data()));
485+
}
486+
487+
TEST(MSGPACK, simple_buffer_ext_pack_convert)
488+
{
489+
std::size_t const size = 65536;
490+
msgpack::sbuffer sbuf;
491+
msgpack::type::ext val1(77, size);
492+
char* buf = val1.data();
493+
for (std::size_t i = 0; i != size; ++i) buf[i] = static_cast<char>(i);
494+
msgpack::pack(sbuf, val1);
495+
496+
msgpack::unpacked ret;
497+
msgpack::unpack(ret, sbuf.data(), sbuf.size());
498+
msgpack::type::ext val2;
499+
ret.get().convert(val2);
500+
EXPECT_EQ(size, val2.size());
501+
EXPECT_EQ(77, val2.type());
502+
EXPECT_TRUE(
503+
std::equal(buf, buf + sizeof(buf), val2.data()));
504+
}
505+
506+
TEST(MSGPACK, simple_buffer_ext_ref_convert)
507+
{
508+
std::size_t const size = 65536;
509+
msgpack::sbuffer sbuf;
510+
msgpack::packer<msgpack::sbuffer> packer(sbuf);
511+
char buf[size];
512+
for (std::size_t i = 0; i != size; ++i) buf[i] = static_cast<char>(i);
513+
packer.pack_ext(sizeof(buf), 77);
514+
packer.pack_ext_body(buf, sizeof(buf));
515+
516+
msgpack::unpacked ret;
517+
msgpack::unpack(ret, sbuf.data(), sbuf.size());
518+
msgpack::type::ext_ref er;
519+
ret.get().convert(er);
520+
EXPECT_EQ(size, er.size());
521+
EXPECT_EQ(77, er.type());
522+
EXPECT_TRUE(
523+
std::equal(buf, buf + sizeof(buf), er.data()));
524+
}
525+
526+
TEST(MSGPACK, simple_buffer_ext_ref_pack_convert)
527+
{
528+
std::size_t const buf_size = 65536;
529+
std::size_t const data_size = buf_size - 1;
530+
msgpack::sbuffer sbuf;
531+
char buf[buf_size];
532+
buf[0] = static_cast<char>(77);
533+
for (std::size_t i = 0; i != data_size; ++i) buf[i + 1] = static_cast<char>(i);
534+
msgpack::pack(sbuf, msgpack::type::ext_ref(buf, buf_size));
535+
536+
msgpack::unpacked ret;
537+
msgpack::unpack(ret, sbuf.data(), sbuf.size());
538+
msgpack::type::ext_ref val2;
539+
ret.get().convert(val2);
540+
EXPECT_EQ(data_size, val2.size());
541+
EXPECT_EQ(77, val2.type());
542+
EXPECT_TRUE(
543+
std::equal(&buf[1], &buf[buf_size], val2.data()));
544+
}
545+
467546
TEST(MSGPACK_STL, simple_buffer_string)
468547
{
469548
for (unsigned int k = 0; k < kLoop; k++) {

0 commit comments

Comments
 (0)