DCCL v4
dccl_native_protobuf.h
1 // Copyright 2019:
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 
40 namespace dccl
41 {
43 namespace native_protobuf
44 {
45 template <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 
57 template <typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType>
59 {
60 };
61 
62 template <typename WireType>
63 struct 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 
79 template <typename WireType>
80 struct 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 
96 template <typename WireType>
97 struct 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 
113 template <typename WireType>
114 struct 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 
130 template <typename WireType>
131 struct 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 
147 template <typename WireType>
148 struct 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 
164 template <typename WireType>
165 struct 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 
180 template <typename WireType>
181 struct 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 
197 template <typename WireType>
198 struct 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 
214 template <typename WireType>
215 struct 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 
230 template <typename WireType>
231 struct 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 
247 template <typename WireType>
248 struct 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 
264 template <typename WireType>
265 struct 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 
281 template <typename WireType>
282 struct 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 
298 template <typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType,
299  typename FieldType = WireType>
300 class 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
dccl::native_protobuf::PrimitiveTypeHelper
Definition: dccl_native_protobuf.h:58
dccl::uint64
google::protobuf::uint64 uint64
an unsigned 64 bit integer
Definition: common.h:60
dccl::Bitset::get_more_bits
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition: bitset.h:419
dccl
Dynamic Compact Control Language namespace.
Definition: any.h:49
dccl::native_protobuf::PrimitiveTypeFieldCodec
Definition: dccl_native_protobuf.h:300
dccl::native_protobuf::EnumFieldCodec::pre_encode
int pre_encode(const google::protobuf::EnumValueDescriptor *const &field_value) override
Convert from the FieldType representation (used in the Google Protobuf message) to the WireType repre...
Definition: dccl_native_protobuf.cpp:150
dccl::Bitset::test
bool test(size_type n) const
Test a bit (return its value)
Definition: bitset.h:223
dccl::Bitset::from_byte_stream
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:340
dccl::NullValueException
Exception used to signal null (non-existent) value within field codecs during decode.
Definition: exception.h:62
dccl::Bitset
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition: bitset.h:41
dccl::TypedFieldCodec
Base class for static-typed (no dccl::any) field encoders/decoders. Most single-valued user defined v...
Definition: field_codec_typed.h:73
dccl::FieldCodecBase::use_required
bool use_required()
Whether to use the required or optional encoding.
Definition: field_codec.h:386
dccl::Bitset::set
Bitset & set(size_type n, bool val=true)
Set a bit to a given value.
Definition: bitset.h:174
dccl::native_protobuf::PrimitiveTypeHelperBase
Definition: dccl_native_protobuf.h:46
dccl::native_protobuf::EnumFieldCodec
Definition: dccl_native_protobuf.h:393
dccl::native_protobuf::EnumFieldCodec::post_decode
const google::protobuf::EnumValueDescriptor * post_decode(const int &wire_value) override
Convert from the WireType representation (used with encode() and decode(), i.e. "on the wire") to the...
Definition: dccl_native_protobuf.cpp:157
dccl::Bitset::to_byte_string
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:296