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