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 #if PROTOBUF_VERSION < 3008000
30 #include <google/protobuf/wire_format_lite_inl.h> // this .h has been removed in protobuf 3.8
31 #endif
32 
33 #include "dccl/field_codec_fixed.h"
34 #include "dccl/field_codec_typed.h"
35 
36 namespace dccl
37 {
39 namespace native_protobuf
40 {
41 
42 template<typename WireType, google::protobuf::internal::WireFormatLite::FieldType DeclaredType>
44 {
45  WireType decode(google::protobuf::io::CodedInputStream* input_stream)
46  {
47  WireType value;
48  google::protobuf::internal::WireFormatLite::ReadPrimitive<WireType, DeclaredType>(input_stream, &value);
49  return value;
50  }
51 };
52 
53 
54 template<typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType>
56 {
57 };
58 
59 template<typename WireType>
60 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_INT64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_INT64>
61 {
62  unsigned byte_size(const WireType& wire_value)
63  { return google::protobuf::internal::WireFormatLite::Int64Size(wire_value); }
64  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
65  { google::protobuf::internal::WireFormatLite::WriteInt64NoTagToArray(wire_value, &(*bytes)[0]); }
66  bool is_varint() { return true; }
67 };
68 
69 template<typename WireType>
70 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_INT32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_INT32>
71 {
72  unsigned byte_size(const WireType& wire_value)
73  { return google::protobuf::internal::WireFormatLite::Int32Size(wire_value); }
74  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
75  { google::protobuf::internal::WireFormatLite::WriteInt32NoTagToArray(wire_value, &(*bytes)[0]); }
76  bool is_varint() { return true; }
77 };
78 
79 
80 template<typename WireType>
81 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_UINT64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_UINT64>
82 {
83  unsigned byte_size(const WireType& wire_value)
84  { return google::protobuf::internal::WireFormatLite::UInt64Size(wire_value); }
85  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
86  { google::protobuf::internal::WireFormatLite::WriteUInt64NoTagToArray(wire_value, &(*bytes)[0]); }
87  bool is_varint() { return true; }
88 };
89 
90 template<typename WireType>
91 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_UINT32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_UINT32>
92 {
93  unsigned byte_size(const WireType& wire_value)
94  { return google::protobuf::internal::WireFormatLite::UInt32Size(wire_value); }
95  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
96  { google::protobuf::internal::WireFormatLite::WriteUInt32NoTagToArray(wire_value, &(*bytes)[0]); }
97  bool is_varint() { return true; }
98 };
99 
100 template<typename WireType>
101 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SINT64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SINT64>
102 {
103  unsigned byte_size(const WireType& wire_value)
104  { return google::protobuf::internal::WireFormatLite::SInt64Size(wire_value); }
105  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
106  { google::protobuf::internal::WireFormatLite::WriteSInt64NoTagToArray(wire_value, &(*bytes)[0]); }
107  bool is_varint() { return true; }
108 };
109 
110 template<typename WireType>
111 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SINT32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SINT32>
112 {
113  unsigned byte_size(const WireType& wire_value)
114  { return google::protobuf::internal::WireFormatLite::SInt32Size(wire_value); }
115  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
116  { google::protobuf::internal::WireFormatLite::WriteSInt32NoTagToArray(wire_value, &(*bytes)[0]); }
117  bool is_varint() { return true; }
118 };
119 
120 
121 
122 template<typename WireType>
123 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_ENUM> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_ENUM>
124 {
125  unsigned byte_size(const WireType& wire_value)
126  { return google::protobuf::internal::WireFormatLite::EnumSize(wire_value); }
127  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
128  { google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(wire_value, &(*bytes)[0]); }
129  bool is_varint() { return true; }
130 };
131 
132 
133 template<typename WireType>
134 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_DOUBLE> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>
135 {
136  unsigned byte_size(const WireType& wire_value)
137  { return google::protobuf::internal::WireFormatLite::kDoubleSize; }
138  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
139  { google::protobuf::internal::WireFormatLite::WriteDoubleNoTagToArray(wire_value, &(*bytes)[0]); }
140  bool is_varint() { return false; }
141 };
142 
143 template<typename WireType>
144 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FLOAT> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_FLOAT>
145 {
146  unsigned byte_size(const WireType& wire_value)
147  { return google::protobuf::internal::WireFormatLite::kFloatSize; }
148  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
149  { google::protobuf::internal::WireFormatLite::WriteFloatNoTagToArray(wire_value, &(*bytes)[0]); }
150  bool is_varint() { return false; }
151 };
152 
153 template<typename WireType>
154 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_BOOL> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_BOOL>
155 {
156  unsigned byte_size(const WireType& wire_value)
157  { return google::protobuf::internal::WireFormatLite::kBoolSize; }
158  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
159  { google::protobuf::internal::WireFormatLite::WriteBoolNoTagToArray(wire_value, &(*bytes)[0]); }
160  bool is_varint() { return false; }
161 };
162 
163 
164 template<typename WireType>
165 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FIXED64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_FIXED64>
166 {
167  unsigned byte_size(const WireType& wire_value)
168  { return google::protobuf::internal::WireFormatLite::kFixed64Size; }
169  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
170  { google::protobuf::internal::WireFormatLite::WriteFixed64NoTagToArray(wire_value, &(*bytes)[0]); }
171  bool is_varint() { return false; }
172 };
173 
174 template<typename WireType>
175 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FIXED32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_FIXED32>
176 {
177  unsigned byte_size(const WireType& wire_value)
178  { return google::protobuf::internal::WireFormatLite::kFixed32Size; }
179  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
180  { google::protobuf::internal::WireFormatLite::WriteFixed32NoTagToArray(wire_value, &(*bytes)[0]); }
181  bool is_varint() { return false; }
182 };
183 
184 template<typename WireType>
185 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SFIXED64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SFIXED64>
186 {
187  unsigned byte_size(const WireType& wire_value)
188  { return google::protobuf::internal::WireFormatLite::kSFixed64Size; }
189  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
190  { google::protobuf::internal::WireFormatLite::WriteSFixed64NoTagToArray(wire_value, &(*bytes)[0]); }
191  bool is_varint() { return false; }
192 };
193 
194 template<typename WireType>
195 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SFIXED32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SFIXED32>
196 {
197  unsigned byte_size(const WireType& wire_value)
198  { return google::protobuf::internal::WireFormatLite::kSFixed32Size; }
199  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
200  { google::protobuf::internal::WireFormatLite::WriteSFixed32NoTagToArray(wire_value, &(*bytes)[0]); }
201  bool is_varint() { return false; }
202 };
203 
204 template<typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType, typename FieldType = WireType>
205 class PrimitiveTypeFieldCodec : public TypedFieldCodec<WireType, FieldType>
206 {
207 private:
208  unsigned presence_bit_size()
209  {
210  return this->use_required() ? 0 : 1;
211  }
212 
213  unsigned min_size()
214  {
215  // if required, minimum size is 1-byte (for varint) or full size (for non-varint)
216  if(this->use_required())
217  {
218  if(helper_.is_varint())
219  return BITS_IN_BYTE;
220  else
221  return BITS_IN_BYTE*helper_.byte_size(WireType());
222  }
223  // if not required, presence bit
224  else
225  {
226  return presence_bit_size();
227  }
228 
229  }
230 
231  unsigned max_size()
232  {
233  // Int32 and Int64 use more space for large negative numbers
234  return std::max<unsigned>(size(std::numeric_limits<WireType>::min()),
235  size(std::numeric_limits<WireType>::max()));
236  }
237 
238  unsigned size()
239  {
240  return min_size();
241  }
242 
243  unsigned size(const WireType& wire_value)
244  {
245  unsigned data_bytes = helper_.byte_size(wire_value);
246  unsigned size = presence_bit_size() + BITS_IN_BYTE*data_bytes;
247  return size;
248  }
249 
250  Bitset encode()
251  {
252  // presence bit, not set
253  return Bitset(min_size(), 0);
254  }
255 
256  Bitset encode(const WireType& wire_value)
257  {
258  std::vector<google::protobuf::uint8> bytes(size(wire_value) / BITS_IN_BYTE, 0);
259 
260  helper_.encode(wire_value, &bytes);
261 
262  Bitset data_bits;
263  data_bits.from_byte_stream(bytes.begin(), bytes.end());
264  if(!this->use_required())
265  {
266  data_bits.resize(data_bits.size() + presence_bit_size());
267  data_bits <<= 1;
268  data_bits.set(0, true); // presence bit
269  }
270  return data_bits;
271  }
272 
273 
274  WireType decode(Bitset* bits)
275  {
276  if(!this->use_required())
277  {
278  dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
279  if(!uint_value) throw NullValueException();
280  bits->resize(0);
281 
282  if(helper_.is_varint())
283  bits->get_more_bits(BITS_IN_BYTE);
284  else
285  bits->get_more_bits(BITS_IN_BYTE*helper_.byte_size(WireType()));
286  }
287 
288  if(helper_.is_varint())
289  {
290  // most significant bit indicates if more bytes are needed
291  while(bits->test(bits->size()-1))
292  bits->get_more_bits(BITS_IN_BYTE);
293  }
294 
295  std::string bytes = bits->to_byte_string();
296  google::protobuf::io::CodedInputStream input_stream(reinterpret_cast<const google::protobuf::uint8*>(bytes.data()), bytes.size());
297 
298  return helper_.decode(&input_stream);
299  }
300 
301 private:
303 
304 };
305 
306 class EnumFieldCodec : public PrimitiveTypeFieldCodec<int, google::protobuf::FieldDescriptor::TYPE_ENUM, const google::protobuf::EnumValueDescriptor*>
307 {
308 public:
309  int pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value);
310  const google::protobuf::EnumValueDescriptor* post_decode(const int& wire_value);
311 };
312 
313 
314 }
315 }
316 
317 
318 
319 #endif
bool test(size_type n) const
Test a bit (return its value)
Definition: bitset.h:230
Exception used to signal null (non-existent) value within field codecs during decode.
Definition: exception.h:40
Bitset & set(size_type n, bool val=true)
Set a bit to a given value.
Definition: bitset.h:176
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
google::protobuf::uint64 uint64
an unsigned 64 bit integer
Definition: common.h:59
Base class for static-typed (no boost::any) field encoders/decoders. Most single-valued user defined ...
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition: bitset.h:447
Dynamic Compact Control Language namespace.
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
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy...
Definition: bitset.h:38