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[0] + 1;
47     }
48     char* data() {
49         return &m_data[0] + 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