DCCL v3
field_codec.cpp
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 #include <boost/algorithm/string.hpp> // for replace_all
23 
24 #include "field_codec.h"
25 #include "exception.h"
26 #include "dccl/codec.h"
27 
28 dccl::MessagePart dccl::FieldCodecBase::part_ =
29  dccl::UNKNOWN;
30 
31 const google::protobuf::Message* dccl::FieldCodecBase::root_message_ = 0;
32 const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor_ = 0;
33 
34 using dccl::dlog;
35 using namespace dccl::logger;
36 
37 //
38 // FieldCodecBase public
39 //
40 dccl::FieldCodecBase::FieldCodecBase() { }
41 
43  const google::protobuf::Message& field_value,
44  MessagePart part)
45 {
46  BaseRAII scoped_globals(part, &field_value);
47 
48  // we pass this through the FromProtoCppTypeBase to do dynamic_cast (RTTI) for
49  // custom message codecs so that these codecs can be written in the derived class (not google::protobuf::Message)
50  field_encode(bits,
51  internal::TypeHelper::find(field_value.GetDescriptor())->get_value(field_value),
52  0);
53 
54 }
55 
57  const boost::any& field_value,
58  const google::protobuf::FieldDescriptor* field)
59 {
60  internal::MessageStack msg_handler(field);
61 
62  if(field)
63  dlog.is(DEBUG2, ENCODE) && dlog << "Starting encode for field: " << field->DebugString() << std::flush;
64 
65  boost::any wire_value;
66  field_pre_encode(&wire_value, field_value);
67 
68  Bitset new_bits;
69  any_encode(&new_bits, wire_value);
70  disp_size(field, new_bits, msg_handler.field_.size());
71  bits->append(new_bits);
72 }
73 
75  const std::vector<boost::any>& field_values,
76  const google::protobuf::FieldDescriptor* field)
77 {
78  internal::MessageStack msg_handler(field);
79 
80  std::vector<boost::any> wire_values;
81  field_pre_encode_repeated(&wire_values, field_values);
82 
83  Bitset new_bits;
84  any_encode_repeated(&new_bits, wire_values);
85  disp_size(field, new_bits, msg_handler.field_.size(), wire_values.size());
86  bits->append(new_bits);
87 }
88 
89 
90 void dccl::FieldCodecBase::base_size(unsigned* bit_size,
91  const google::protobuf::Message& msg,
92  MessagePart part)
93 {
94  BaseRAII scoped_globals(part, &msg);
95 
96  *bit_size = 0;
97 
98  field_size(bit_size, &msg, 0);
99 
100 }
101 
102 void dccl::FieldCodecBase::field_size(unsigned* bit_size,
103  const boost::any& field_value,
104  const google::protobuf::FieldDescriptor* field)
105 {
106  internal::MessageStack msg_handler(field);
107 
108  boost::any wire_value;
109  field_pre_encode(&wire_value, field_value);
110 
111  *bit_size += any_size(wire_value);
112 }
113 
115  const std::vector<boost::any>& field_values,
116  const google::protobuf::FieldDescriptor* field)
117 {
118  internal::MessageStack msg_handler(field);
119 
120  std::vector<boost::any> wire_values;
121  field_pre_encode_repeated(&wire_values, field_values);
122 
123  *bit_size += any_size_repeated(wire_values);
124 }
125 
126 
127 
128 
130  google::protobuf::Message* field_value,
131  MessagePart part)
132 {
133  BaseRAII scoped_globals(part, field_value);
134  boost::any value(field_value);
135  field_decode(bits, &value, 0);
136 }
137 
138 
140  boost::any* field_value,
141  const google::protobuf::FieldDescriptor* field)
142 {
143  internal::MessageStack msg_handler(field);
144 
145  if(!field_value)
146  throw(Exception("Decode called with NULL boost::any"));
147  else if(!bits)
148  throw(Exception("Decode called with NULL Bitset"));
149 
150  if(field)
151  dlog.is(DEBUG2, DECODE) && dlog << "Starting decode for field: " << field->DebugString() << std::flush;
152 
153  if(root_message())
154  dlog.is(DEBUG3, DECODE) && dlog << "Message thus far is: " << root_message()->DebugString() << std::flush;
155 
156  Bitset these_bits(bits);
157 
158  unsigned bits_to_transfer = 0;
159  field_min_size(&bits_to_transfer, field);
160  these_bits.get_more_bits(bits_to_transfer);
161 
162  dlog.is(DEBUG2, DECODE) && dlog << "... using these bits: " << these_bits << std::endl;
163 
164  boost::any wire_value = *field_value;
165 
166  any_decode(&these_bits, &wire_value);
167 
168  field_post_decode(wire_value, field_value);
169 }
170 
172  std::vector<boost::any>* field_values,
173  const google::protobuf::FieldDescriptor* field)
174 {
175  internal::MessageStack msg_handler(field);
176 
177  if(!field_values)
178  throw(Exception("Decode called with NULL field_values"));
179  else if(!bits)
180  throw(Exception("Decode called with NULL Bitset"));
181 
182  if(field)
183  dlog.is(DEBUG2, DECODE) && dlog << "Starting repeated decode for field: " << field->DebugString();
184 
185  Bitset these_bits(bits);
186 
187  unsigned bits_to_transfer = 0;
188  field_min_size(&bits_to_transfer, field);
189  these_bits.get_more_bits(bits_to_transfer);
190 
191  dlog.is(DEBUG2, DECODE) && dlog << "using these " <<
192  these_bits.size() << " bits: " << these_bits << std::endl;
193 
194  std::vector<boost::any> wire_values = *field_values;
195  any_decode_repeated(&these_bits, &wire_values);
196 
197  field_values->clear();
198  field_post_decode_repeated(wire_values, field_values);
199 }
200 
201 
202 void dccl::FieldCodecBase::base_max_size(unsigned* bit_size,
203  const google::protobuf::Descriptor* desc,
204  MessagePart part)
205 {
206  BaseRAII scoped_globals(part, desc);
207  *bit_size = 0;
208 
209  internal::MessageStack msg_handler;
210  if(desc)
211  msg_handler.push(desc);
212  else
213  throw(Exception("Max Size called with NULL Descriptor"));
214 
215  field_max_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(0));
216 }
217 
218 void dccl::FieldCodecBase::field_max_size(unsigned* bit_size,
219  const google::protobuf::FieldDescriptor* field)
220 {
221  internal::MessageStack msg_handler(field);
222 
223  if(this_field())
224  *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
225  else
226  *bit_size += max_size();
227 }
228 
229 
230 
231 void dccl::FieldCodecBase::base_min_size(unsigned* bit_size,
232  const google::protobuf::Descriptor* desc,
233  MessagePart part)
234 {
235  BaseRAII scoped_globals(part, desc);
236 
237  *bit_size = 0;
238 
239  internal::MessageStack msg_handler;
240  if(desc)
241  msg_handler.push(desc);
242  else
243  throw(Exception("Min Size called with NULL Descriptor"));
244 
245  field_min_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(0));
246 }
247 
248 void dccl::FieldCodecBase::field_min_size(unsigned* bit_size,
249  const google::protobuf::FieldDescriptor* field)
250 
251 {
252  internal::MessageStack msg_handler(field);
253 
254  if(this_field())
255  *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
256  else
257  *bit_size += min_size();
258 }
259 
260 
261 void dccl::FieldCodecBase::base_validate(const google::protobuf::Descriptor* desc,
262  MessagePart part)
263 {
264  BaseRAII scoped_globals(part, desc);
265 
266  internal::MessageStack msg_handler;
267  if(desc)
268  msg_handler.push(desc);
269  else
270  throw(Exception("Validate called with NULL Descriptor"));
271 
272  bool b = false;
273  field_validate(&b, static_cast<google::protobuf::FieldDescriptor*>(0));
274 }
275 
276 
278  const google::protobuf::FieldDescriptor* field)
279 {
280  internal::MessageStack msg_handler(field);
281 
282  if(field && dccl_field_options().in_head() && variable_size())
283  throw(Exception("Variable size codec used in header - header fields must be encoded with fixed size codec."));
284 
285  validate();
286 }
287 
288 void dccl::FieldCodecBase::base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessagePart part)
289 {
290  BaseRAII scoped_globals(part, desc);
291 
292  internal::MessageStack msg_handler;
293  if(desc)
294  msg_handler.push(desc);
295  else
296  throw(Exception("info called with NULL Descriptor"));
297 
298  field_info(os, static_cast<google::protobuf::FieldDescriptor*>(0));
299 }
300 
301 
302 void dccl::FieldCodecBase::field_info(std::ostream* os,
303  const google::protobuf::FieldDescriptor* field)
304 {
305  internal::MessageStack msg_handler(field);
306 
307 
308  std::stringstream ss;
309  int depth = msg_handler.count();
310 
311  std::string name = ((this_field()) ? boost::lexical_cast<std::string>(this_field()->number()) + ". " + this_field()->name() : this_descriptor()->full_name());
312  if(this_field() && this_field()->is_repeated())
313  name += "[" + boost::lexical_cast<std::string>(dccl_field_options().max_repeat()) + "]";
314 
315 
316  if(!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
317  depth -= 1;
318 
319  const int spaces = 8;
320  std::string indent = std::string(spaces*(depth),' ');
321 
322  const int full_width = 40;
323 
324  bool is_zero_size = false;
325 
326  std::stringstream range;
327  if(variable_size())
328  {
329  unsigned max_sz = 0, min_sz = 0;
330  field_max_size(&max_sz, field);
331  field_min_size(&min_sz, field);
332  if(!max_sz) is_zero_size = true;
333  range << min_sz << "-" << max_sz;
334  }
335  else
336  {
337  unsigned sz = 0;
338  field_max_size(&sz, field);
339  if(!sz) is_zero_size = true;
340  range << sz;
341  }
342 
343  int width = this_field() ? full_width-name.size() : full_width-name.size()+spaces;
344  ss << indent << name <<
345  std::setfill('.') << std::setw(std::max(1, width)) << range.str()
346  << " {" << (this_field() ? FieldCodecManager::find(this_field(), has_codec_group(), codec_group())->name() : FieldCodecManager::find(root_descriptor_)->name()) << "}";
347 
348 
349 
350 // std::string s = ss.str();
351 // boost::replace_all(s, "\n", "\n" + indent);
352 // s = indent + s;
353 
354 
355  if(!is_zero_size)
356  *os << ss.str() << "\n";
357 
358  std::string specific_info = info();
359  if(!specific_info.empty())
360  *os << specific_info;
361 
362 }
363 
364 std::string dccl::FieldCodecBase::codec_group(const google::protobuf::Descriptor* desc)
365 {
366  if(desc->options().GetExtension(dccl::msg).has_codec_group())
367  return desc->options().GetExtension(dccl::msg).codec_group();
368  else
369  return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
370 }
371 
372 
373 //
374 // FieldCodecBase protected
375 //
376 
378 {
379  return std::string();
380 }
381 
382 void dccl::FieldCodecBase::any_encode_repeated(dccl::Bitset* bits, const std::vector<boost::any>& wire_values)
383 {
384  // out_bits = [field_values[2]][field_values[1]][field_values[0]]
385 
386  unsigned wire_vector_size = dccl_field_options().max_repeat();
387 
388  // for DCCL3 and beyond, add a prefix numeric field giving the vector size (rather than always going to max_repeat
389  if(codec_version() > 2)
390  {
391  wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size());
392  Bitset size_bits(repeated_vector_field_size(dccl_field_options().max_repeat()), wire_values.size());
393  bits->append(size_bits);
394  }
395 
396  for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
397  {
398  Bitset new_bits;
399  if(i < wire_values.size())
400  any_encode(&new_bits, wire_values[i]);
401  else
402  any_encode(&new_bits, boost::any());
403  bits->append(new_bits);
404 
405  }
406 }
407 
408 
409 
410 void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* wire_values)
411 {
412 
413  unsigned wire_vector_size = dccl_field_options().max_repeat();
414  if(codec_version() > 2)
415  {
416  Bitset size_bits(repeated_bits);
417  size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().max_repeat()));
418 
419  wire_vector_size = size_bits.to_ulong();
420  }
421 
422  wire_values->resize(wire_vector_size);
423 
424  for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
425  {
426  Bitset these_bits(repeated_bits);
427  these_bits.get_more_bits(min_size());
428  any_decode(&these_bits, &(*wire_values)[i]);
429  }
430 }
431 
432 unsigned dccl::FieldCodecBase::any_size_repeated(const std::vector<boost::any>& wire_values)
433 {
434  unsigned out = 0;
435  unsigned wire_vector_size = dccl_field_options().max_repeat();
436 
437  if(codec_version() > 2)
438  {
439  wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size());
440  out += repeated_vector_field_size(dccl_field_options().max_repeat());
441  }
442 
443  for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
444  {
445  if(i < wire_values.size())
446  out += any_size(wire_values[i]);
447  else
448  out += any_size(boost::any());
449  }
450  return out;
451 }
452 
453 unsigned dccl::FieldCodecBase::max_size_repeated()
454 {
455  if(!dccl_field_options().has_max_repeat())
456  throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field: " + this_field()->DebugString()));
457  else if(codec_version() > 2)
458  return repeated_vector_field_size(dccl_field_options().max_repeat()) + max_size() * dccl_field_options().max_repeat();
459  else
460  return max_size() * dccl_field_options().max_repeat();
461 }
462 
463 unsigned dccl::FieldCodecBase::min_size_repeated()
464 {
465  if(!dccl_field_options().has_max_repeat())
466  throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field " + this_field()->DebugString()));
467  else if(codec_version() > 2)
468  return repeated_vector_field_size(dccl_field_options().max_repeat());
469  else
470  return min_size() * dccl_field_options().max_repeat();
471 }
472 
473 void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<boost::any>* wire_values, const std::vector<boost::any>& field_values)
474 {
475  for(std::vector<boost::any>::const_iterator it = field_values.begin(),
476  end = field_values.end(); it != end; ++it)
477  {
478  boost::any wire_value;
479  any_pre_encode(&wire_value, *it);
480  wire_values->push_back(wire_value);
481  }
482 
483 }
484 void dccl::FieldCodecBase::any_post_decode_repeated(
485  const std::vector<boost::any>& wire_values, std::vector<boost::any>* field_values)
486 {
487  for(std::vector<boost::any>::const_iterator it = wire_values.begin(),
488  end = wire_values.end(); it != end; ++it)
489  {
490  boost::any field_value;
491  any_post_decode(*it, &field_value);
492  field_values->push_back(field_value);
493  }
494 }
495 
496 
497 //
498 // FieldCodecBase private
499 //
500 
501 void dccl::FieldCodecBase::disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size /* = -1 */)
502 {
503  if(!root_descriptor_)
504  return;
505 
506  if(dlog.is(INFO, SIZE))
507  {
508  std::string name = ((field) ? field->name() : root_descriptor_->full_name());
509  if(vector_size >= 0)
510  name += "[" + boost::lexical_cast<std::string>(vector_size) + "]";
511 
512 
513  dlog << std::string(depth, '|') << name << std::setfill('.') << std::setw(40-name.size()-depth) << new_bits.size() << std::endl;
514 
515  if(!field)
516  dlog << std::endl;
517 
518  }
519 }
Bitset & append(const Bitset &bits)
Adds the bitset to the big end.
Definition: bitset.h:381
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
unsigned long to_ulong() const
Returns the value of the Bitset as an unsigned long integer. Equivalent to to<unsigned long>()...
Definition: bitset.h:284
void field_validate(bool *b, const google::protobuf::FieldDescriptor *field)
Validate this field, checking that all required option extensions are set (e.g. (dccl.field).max and (dccl.field).min for arithmetic codecs)
void field_decode_repeated(Bitset *bits, std::vector< boost::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
void field_min_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the lower bound on this field&#39;s size (in bits)
void base_size(unsigned *bit_size, const google::protobuf::Message &msg, MessagePart part)
Calculate the size (in bits) of a part of the base message when it is encoded.
Definition: field_codec.cpp:90
void base_encode(Bitset *bits, const google::protobuf::Message &msg, MessagePart part)
Encode this part (body or head) of the base message.
Definition: field_codec.cpp:42
void base_min_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the minimum size of a message given its Descriptor alone (no data)
void field_decode(Bitset *bits, boost::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
static boost::shared_ptr< FieldCodecBase > find(const google::protobuf::FieldDescriptor *field, bool has_codec_group, const std::string &codec_group)
Find the codec for a given field. For embedded messages, prefers (dccl.field).codec (inside field) ov...
void field_size(unsigned *bit_size, const boost::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
void field_encode_repeated(Bitset *bits, const std::vector< boost::any > &field_values, const google::protobuf::FieldDescriptor *field)
Encode a repeated field.
Definition: field_codec.cpp:74
void base_max_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the maximum size of a message given its Descriptor alone (no data)
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition: bitset.h:447
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
void field_info(std::ostream *os, const google::protobuf::FieldDescriptor *field)
Write human readable information about the field and its bounds to the provided stream.
void field_size_repeated(unsigned *bit_size, const std::vector< boost::any > &wire_values, const google::protobuf::FieldDescriptor *field)
Calculate the size of a repeated field.
void base_info(std::ostream *os, const google::protobuf::Descriptor *desc, MessagePart part)
Get human readable information (size of fields, etc.) about this part of the DCCL message...
void base_validate(const google::protobuf::Descriptor *desc, MessagePart part)
Validate this part of the message to make sure all required extensions are set.
bool is(logger::Verbosity verbosity, logger::Group group=logger::GENERAL)
Indicates the verbosity of the Logger until the next std::flush or std::endl. The boolean return is u...
Definition: logger.h:145
Exception class for DCCL.
Definition: exception.h:30
void field_encode(Bitset *bits, const boost::any &field_value, const google::protobuf::FieldDescriptor *field)
Encode a non-repeated field.
Definition: field_codec.cpp:56
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy...
Definition: bitset.h:38
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field&#39;s size (in bits)