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