DCCL v4
Loading...
Searching...
No Matches
dccl_native_protobuf.h
1// Copyright 2019-2023:
2// GobySoft, LLC (2013-)
3// Community contributors (see AUTHORS file)
4// File authors:
5// Toby Schneider <toby@gobysoft.org>
6// Russ <russ@rw.id.au>
7//
8//
9// This file is part of the Dynamic Compact Control Language Library
10// ("DCCL").
11//
12// DCCL is free software: you can redistribute it and/or modify
13// it under the terms of the GNU Lesser General Public License as published by
14// the Free Software Foundation, either version 2.1 of the License, or
15// (at your option) any later version.
16//
17// DCCL is distributed in the hope that it will be useful,
18// but WITHOUT ANY WARRANTY; without even the implied warranty of
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20// GNU Lesser General Public License for more details.
21//
22// You should have received a copy of the GNU Lesser General Public License
23// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
24#ifndef DCCL_NATIVE_PROTOBUF_20190218H
25#define DCCL_NATIVE_PROTOBUF_20190218H
26
27#include <google/protobuf/io/coded_stream.h>
28#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
29#include <google/protobuf/unknown_field_set.h>
30#include <google/protobuf/wire_format_lite.h>
31
32#include <google/protobuf/stubs/common.h>
33#if GOOGLE_PROTOBUF_VERSION < 3008000
34#include <google/protobuf/wire_format_lite_inl.h> // this .h has been removed in protobuf 3.8
35#endif
36
37#include "../field_codec_fixed.h"
38#include "../field_codec_typed.h"
39
40namespace dccl
41{
43namespace native_protobuf
44{
45template <typename WireType, google::protobuf::internal::WireFormatLite::FieldType DeclaredType>
47{
48 WireType decode(google::protobuf::io::CodedInputStream* input_stream)
49 {
50 WireType value;
51 google::protobuf::internal::WireFormatLite::ReadPrimitive<WireType, DeclaredType>(
52 input_stream, &value);
53 return value;
54 }
55};
56
57template <typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType>
59{
60};
61
62template <typename WireType>
63struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_INT64>
64 : public PrimitiveTypeHelperBase<WireType,
65 google::protobuf::internal::WireFormatLite::TYPE_INT64>
66{
67 unsigned byte_size(const WireType& wire_value)
68 {
69 return google::protobuf::internal::WireFormatLite::Int64Size(wire_value);
70 }
71 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
72 {
73 google::protobuf::internal::WireFormatLite::WriteInt64NoTagToArray(wire_value,
74 &(*bytes)[0]);
75 }
76 bool is_varint() { return true; }
77};
78
79template <typename WireType>
80struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_INT32>
81 : public PrimitiveTypeHelperBase<WireType,
82 google::protobuf::internal::WireFormatLite::TYPE_INT32>
83{
84 unsigned byte_size(const WireType& wire_value)
85 {
86 return google::protobuf::internal::WireFormatLite::Int32Size(wire_value);
87 }
88 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
89 {
90 google::protobuf::internal::WireFormatLite::WriteInt32NoTagToArray(wire_value,
91 &(*bytes)[0]);
92 }
93 bool is_varint() { return true; }
94};
95
96template <typename WireType>
97struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_UINT64>
98 : public PrimitiveTypeHelperBase<WireType,
99 google::protobuf::internal::WireFormatLite::TYPE_UINT64>
100{
101 unsigned byte_size(const WireType& wire_value)
102 {
103 return google::protobuf::internal::WireFormatLite::UInt64Size(wire_value);
104 }
105 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
106 {
107 google::protobuf::internal::WireFormatLite::WriteUInt64NoTagToArray(wire_value,
108 &(*bytes)[0]);
109 }
110 bool is_varint() { return true; }
111};
112
113template <typename WireType>
114struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_UINT32>
115 : public PrimitiveTypeHelperBase<WireType,
116 google::protobuf::internal::WireFormatLite::TYPE_UINT32>
117{
118 unsigned byte_size(const WireType& wire_value)
119 {
120 return google::protobuf::internal::WireFormatLite::UInt32Size(wire_value);
121 }
122 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
123 {
124 google::protobuf::internal::WireFormatLite::WriteUInt32NoTagToArray(wire_value,
125 &(*bytes)[0]);
126 }
127 bool is_varint() { return true; }
128};
129
130template <typename WireType>
131struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SINT64>
132 : public PrimitiveTypeHelperBase<WireType,
133 google::protobuf::internal::WireFormatLite::TYPE_SINT64>
134{
135 unsigned byte_size(const WireType& wire_value)
136 {
137 return google::protobuf::internal::WireFormatLite::SInt64Size(wire_value);
138 }
139 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
140 {
141 google::protobuf::internal::WireFormatLite::WriteSInt64NoTagToArray(wire_value,
142 &(*bytes)[0]);
143 }
144 bool is_varint() { return true; }
145};
146
147template <typename WireType>
148struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SINT32>
149 : public PrimitiveTypeHelperBase<WireType,
150 google::protobuf::internal::WireFormatLite::TYPE_SINT32>
151{
152 unsigned byte_size(const WireType& wire_value)
153 {
154 return google::protobuf::internal::WireFormatLite::SInt32Size(wire_value);
155 }
156 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
157 {
158 google::protobuf::internal::WireFormatLite::WriteSInt32NoTagToArray(wire_value,
159 &(*bytes)[0]);
160 }
161 bool is_varint() { return true; }
162};
163
164template <typename WireType>
165struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_ENUM>
166 : public PrimitiveTypeHelperBase<WireType,
167 google::protobuf::internal::WireFormatLite::TYPE_ENUM>
168{
169 unsigned byte_size(const WireType& wire_value)
170 {
171 return google::protobuf::internal::WireFormatLite::EnumSize(wire_value);
172 }
173 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
174 {
175 google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(wire_value, &(*bytes)[0]);
176 }
177 bool is_varint() { return true; }
178};
179
180template <typename WireType>
181struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_DOUBLE>
182 : public PrimitiveTypeHelperBase<WireType,
183 google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>
184{
185 unsigned byte_size(const WireType& /*wire_value*/)
186 {
187 return google::protobuf::internal::WireFormatLite::kDoubleSize;
188 }
189 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
190 {
191 google::protobuf::internal::WireFormatLite::WriteDoubleNoTagToArray(wire_value,
192 &(*bytes)[0]);
193 }
194 bool is_varint() { return false; }
195};
196
197template <typename WireType>
198struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FLOAT>
199 : public PrimitiveTypeHelperBase<WireType,
200 google::protobuf::internal::WireFormatLite::TYPE_FLOAT>
201{
202 unsigned byte_size(const WireType& /*wire_value*/)
203 {
204 return google::protobuf::internal::WireFormatLite::kFloatSize;
205 }
206 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
207 {
208 google::protobuf::internal::WireFormatLite::WriteFloatNoTagToArray(wire_value,
209 &(*bytes)[0]);
210 }
211 bool is_varint() { return false; }
212};
213
214template <typename WireType>
215struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_BOOL>
216 : public PrimitiveTypeHelperBase<WireType,
217 google::protobuf::internal::WireFormatLite::TYPE_BOOL>
218{
219 unsigned byte_size(const WireType& /*wire_value*/)
220 {
221 return google::protobuf::internal::WireFormatLite::kBoolSize;
222 }
223 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
224 {
225 google::protobuf::internal::WireFormatLite::WriteBoolNoTagToArray(wire_value, &(*bytes)[0]);
226 }
227 bool is_varint() { return false; }
228};
229
230template <typename WireType>
231struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FIXED64>
232 : public PrimitiveTypeHelperBase<WireType,
233 google::protobuf::internal::WireFormatLite::TYPE_FIXED64>
234{
235 unsigned byte_size(const WireType& /*wire_value*/)
236 {
237 return google::protobuf::internal::WireFormatLite::kFixed64Size;
238 }
239 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
240 {
241 google::protobuf::internal::WireFormatLite::WriteFixed64NoTagToArray(wire_value,
242 &(*bytes)[0]);
243 }
244 bool is_varint() { return false; }
245};
246
247template <typename WireType>
248struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FIXED32>
249 : public PrimitiveTypeHelperBase<WireType,
250 google::protobuf::internal::WireFormatLite::TYPE_FIXED32>
251{
252 unsigned byte_size(const WireType& /*wire_value*/)
253 {
254 return google::protobuf::internal::WireFormatLite::kFixed32Size;
255 }
256 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
257 {
258 google::protobuf::internal::WireFormatLite::WriteFixed32NoTagToArray(wire_value,
259 &(*bytes)[0]);
260 }
261 bool is_varint() { return false; }
262};
263
264template <typename WireType>
265struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SFIXED64>
266 : public PrimitiveTypeHelperBase<WireType,
267 google::protobuf::internal::WireFormatLite::TYPE_SFIXED64>
268{
269 unsigned byte_size(const WireType& /*wire_value*/)
270 {
271 return google::protobuf::internal::WireFormatLite::kSFixed64Size;
272 }
273 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
274 {
275 google::protobuf::internal::WireFormatLite::WriteSFixed64NoTagToArray(wire_value,
276 &(*bytes)[0]);
277 }
278 bool is_varint() { return false; }
279};
280
281template <typename WireType>
282struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SFIXED32>
283 : public PrimitiveTypeHelperBase<WireType,
284 google::protobuf::internal::WireFormatLite::TYPE_SFIXED32>
285{
286 unsigned byte_size(const WireType& /*wire_value*/)
287 {
288 return google::protobuf::internal::WireFormatLite::kSFixed32Size;
289 }
290 void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
291 {
292 google::protobuf::internal::WireFormatLite::WriteSFixed32NoTagToArray(wire_value,
293 &(*bytes)[0]);
294 }
295 bool is_varint() { return false; }
296};
297
298template <typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType,
299 typename FieldType = WireType>
300class PrimitiveTypeFieldCodec : public TypedFieldCodec<WireType, FieldType>
301{
302 private:
303 unsigned presence_bit_size() { return this->use_required() ? 0 : 1; }
304
305 unsigned min_size() override
306 {
307 // if required, minimum size is 1-byte (for varint) or full size (for non-varint)
308 if (this->use_required())
309 {
310 if (helper_.is_varint())
311 return BITS_IN_BYTE;
312 else
313 return BITS_IN_BYTE * helper_.byte_size(WireType());
314 }
315 // if not required, presence bit
316 else
317 {
318 return presence_bit_size();
319 }
320 }
321
322 unsigned max_size() override
323 {
324 // Int32 and Int64 use more space for large negative numbers
325 return std::max<unsigned>(size(std::numeric_limits<WireType>::min()),
326 size(std::numeric_limits<WireType>::max()));
327 }
328
329 unsigned size() override { return min_size(); }
330
331 unsigned size(const WireType& wire_value) override
332 {
333 unsigned data_bytes = helper_.byte_size(wire_value);
334 unsigned size = presence_bit_size() + BITS_IN_BYTE * data_bytes;
335 return size;
336 }
337
338 Bitset encode() override
339 {
340 // presence bit, not set
341 return Bitset(min_size(), 0);
342 }
343
344 Bitset encode(const WireType& wire_value) override
345 {
346 std::vector<google::protobuf::uint8> bytes(size(wire_value) / BITS_IN_BYTE, 0);
347
348 helper_.encode(wire_value, &bytes);
349
350 Bitset data_bits;
351 data_bits.from_byte_stream(bytes.begin(), bytes.end());
352 if (!this->use_required())
353 {
354 data_bits.resize(data_bits.size() + presence_bit_size());
355 data_bits <<= 1;
356 data_bits.set(0, true); // presence bit
357 }
358 return data_bits;
359 }
360
361 WireType decode(Bitset* bits) override
362 {
363 if (!this->use_required())
364 {
365 dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
366 if (!uint_value)
367 throw NullValueException();
368 bits->resize(0);
369
370 if (helper_.is_varint())
371 bits->get_more_bits(BITS_IN_BYTE);
372 else
373 bits->get_more_bits(BITS_IN_BYTE * helper_.byte_size(WireType()));
374 }
375
376 if (helper_.is_varint())
377 {
378 // most significant bit indicates if more bytes are needed
379 while (bits->test(bits->size() - 1)) bits->get_more_bits(BITS_IN_BYTE);
380 }
381
382 std::string bytes = bits->to_byte_string();
383 google::protobuf::io::CodedInputStream input_stream(
384 reinterpret_cast<const google::protobuf::uint8*>(bytes.data()), bytes.size());
385
386 return helper_.decode(&input_stream);
387 }
388
389 private:
391};
392
394 : public PrimitiveTypeFieldCodec<int, google::protobuf::FieldDescriptor::TYPE_ENUM,
395 const google::protobuf::EnumValueDescriptor*>
396{
397 public:
398 int pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value) override;
399 const google::protobuf::EnumValueDescriptor* post_decode(const int& wire_value) override;
400};
401
402} // namespace native_protobuf
403} // namespace dccl
404
405#endif
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition bitset.h:43
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition bitset.h:420
bool test(size_type n) const
Test a bit (return its value)
Definition bitset.h:224
std::string to_byte_string()
Returns the value of the Bitset to a byte string, where each character represents 8 bits of the Bitse...
Definition bitset.h:297
Bitset & set(size_type n, bool val=true)
Set a bit to a given value.
Definition bitset.h:175
void from_byte_stream(CharIterator begin, CharIterator end)
Sets the value of the Bitset to the contents of a byte string, where each character represents 8 bits...
Definition bitset.h:341
bool use_required()
Whether to use the required or optional encoding.
Exception used to signal null (non-existent) value within field codecs during decode.
Definition exception.h:62
Base class for static-typed (no dccl::any) field encoders/decoders. Most single-valued user defined v...
Dynamic Compact Control Language namespace.
Definition any.h:47
google::protobuf::uint64 uint64
an unsigned 64 bit integer
Definition common.h:60