DCCL v4
field_codec_typed.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 DCCLFIELDCODECTYPED20120312H
23 #define DCCLFIELDCODECTYPED20120312H
24 
25 
26 #include <boost/type_traits.hpp>
27 
28 #include "field_codec.h"
29 
30 namespace dccl
31 {
32 
34  namespace compiler
35  {
37  template <int> struct dummy { dummy(int) {} };
38  }
39 
41  template <typename WireType, typename FieldType, class Enable = void>
43  {
44  public:
49  virtual WireType pre_encode(const FieldType& field_value) = 0;
50 
55  virtual FieldType post_decode(const WireType& wire_value) = 0;
56  };
57 
58 
60  template <typename WireType, typename FieldType>
61  class FieldCodecSelector<WireType, FieldType,
62  typename boost::enable_if<boost::is_same<WireType, FieldType> >::type>
63  : public FieldCodecBase
64  {
65  public:
67  virtual WireType pre_encode(const FieldType& field_value)
68  { return field_value; }
70  virtual FieldType post_decode(const WireType& wire_value)
71  { return wire_value; }
72  };
73 
74 
75 
81  template<typename WireType, typename FieldType = WireType>
82  class TypedFieldCodec : public FieldCodecSelector<WireType, FieldType>
83  {
84  public:
85 typedef WireType wire_type;
86  typedef FieldType field_type;
87 
88  public:
89 
93  virtual Bitset encode() = 0;
94 
99  virtual Bitset encode(const WireType& wire_value) = 0;
100 
105  virtual WireType decode(Bitset* bits) = 0;
106 
110  virtual unsigned size() = 0;
111 
116  virtual unsigned size(const WireType& wire_value) = 0;
117 
118  private:
119  unsigned any_size(const boost::any& wire_value)
120  {
121  try
122  { return wire_value.empty() ? size() : size(boost::any_cast<WireType>(wire_value)); }
123  catch(boost::bad_any_cast&)
124  { throw(type_error("size", typeid(WireType), wire_value.type())); }
125  }
126 
127  void any_encode(Bitset* bits, const boost::any& wire_value)
128  {
129  try
130  { *bits = wire_value.empty() ? encode() : encode(boost::any_cast<WireType>(wire_value)); }
131  catch(boost::bad_any_cast&)
132  { throw(type_error("encode", typeid(WireType), wire_value.type())); }
133  }
134 
135  void any_decode(Bitset* bits, boost::any* wire_value)
136  {
137  any_decode_specific<WireType>(bits, wire_value);
138  }
139 
140 
141 
142  void any_pre_encode(boost::any* wire_value,
143  const boost::any& field_value)
144  {
145  try
146  {
147  if(!field_value.empty())
148  *wire_value = this->pre_encode(boost::any_cast<FieldType>(field_value));
149  }
150  catch(boost::bad_any_cast&)
151  {
152  throw(type_error("pre_encode", typeid(FieldType), field_value.type()));
153  }
154  catch(NullValueException&)
155  {
156  *wire_value = boost::any();
157  }
158  }
159 
160  void any_post_decode(const boost::any& wire_value,
161  boost::any* field_value)
162  {
163  any_post_decode_specific<WireType>(wire_value, field_value);
164  }
165 
166 
167  // we don't currently support type conversion (post_decode / pre_encode) of Message types
168  template<typename T>
169  typename boost::enable_if<boost::is_base_of<google::protobuf::Message, T>, void>::type
170  any_post_decode_specific(const boost::any& wire_value, boost::any* field_value, compiler::dummy<0> dummy = 0)
171  { *field_value = wire_value; }
172 
173  template<typename T>
174  typename boost::disable_if<boost::is_base_of<google::protobuf::Message, T>, void>::type
175  any_post_decode_specific(const boost::any& wire_value, boost::any* field_value, compiler::dummy<1> dummy = 0)
176  {
177  try
178  {
179  if(!wire_value.empty())
180  *field_value = this->post_decode(boost::any_cast<WireType>(wire_value));
181  }
182  catch(boost::bad_any_cast&)
183  {
184  throw(type_error("post_decode", typeid(WireType), wire_value.type()));
185  }
186  catch(NullValueException&)
187  {
188  *field_value = boost::any();
189  }
190  }
191 
192 
193  template<typename T>
194  typename boost::enable_if<boost::is_base_of<google::protobuf::Message, T>, void>::type
195  any_decode_specific(Bitset* bits, boost::any* wire_value, compiler::dummy<0> dummy = 0)
196  {
197  try
198  {
199  google::protobuf::Message* msg = boost::any_cast<google::protobuf::Message* >(*wire_value);
200  msg->CopyFrom(decode(bits));
201  }
202  catch(NullValueException&)
203  {
205  *wire_value = boost::any();
206  }
207  }
208 
209  template<typename T>
210  typename boost::disable_if<boost::is_base_of<google::protobuf::Message, T>, void>::type
211  any_decode_specific(Bitset* bits, boost::any* wire_value, compiler::dummy<1> dummy = 0)
212  {
213  try
214  { *wire_value = decode(bits); }
215  catch(NullValueException&)
216  { *wire_value = boost::any(); }
217  }
218 
219  };
220 
221 
227  template<typename WireType, typename FieldType = WireType>
228  class RepeatedTypedFieldCodec : public TypedFieldCodec<WireType, FieldType>
229  {
230  public:
231  typedef WireType wire_type;
232  typedef FieldType field_type;
233 
234  public:
236  virtual Bitset encode_repeated(const std::vector<WireType>& wire_value) = 0;
237 
239  virtual std::vector<WireType> decode_repeated(Bitset* bits) = 0;
240 
242  virtual unsigned size_repeated(
243  const std::vector<WireType>& wire_values) = 0;
244 
246  virtual unsigned max_size_repeated() = 0;
247 
249  virtual unsigned min_size_repeated() = 0;
250 
251 
255  virtual Bitset encode()
256  { return encode_repeated(std::vector<WireType>()); }
257 
262  virtual Bitset encode(const WireType& wire_value)
263  { return encode_repeated(std::vector<WireType>(1, wire_value)); }
264 
269  virtual WireType decode(dccl::Bitset* bits)
270  {
271  std::vector<WireType> return_vec = decode_repeated(bits);
272  if(return_vec.empty())
273  throw dccl::NullValueException();
274  else
275  return return_vec.at(0);
276  }
277 
281  virtual unsigned size()
282  { return size_repeated(std::vector<WireType>()); }
283 
288  virtual unsigned size(const WireType& wire_value)
289  { return size_repeated(std::vector<WireType>(1, wire_value)); }
290 
291  virtual unsigned max_size()
292  { return max_size_repeated(); }
293 
294  virtual unsigned min_size()
295  { return min_size_repeated(); }
296 
297 
298  private:
299  void any_encode_repeated(Bitset* bits, const std::vector<boost::any>& wire_values)
300  {
301  try
302  {
303  std::vector<WireType> in;
304  for (std::vector<boost::any>::const_iterator it = wire_values.begin(); it != wire_values.end(); ++it)
305  {
306  in.push_back(boost::any_cast<WireType>(*it));
307  }
308 
309  *bits = encode_repeated(in);
310  }
311  catch(boost::bad_any_cast&)
312  { throw(type_error("encode_repeated", typeid(WireType), wire_values.at(0).type())); }
313  }
314 
315  void any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* field_values)
316  {
317  any_decode_repeated_specific<WireType>(repeated_bits, field_values);
318  }
319 
320  template<typename T>
321  typename boost::enable_if<boost::is_base_of<google::protobuf::Message, T>, void>::type
322  any_decode_repeated_specific(Bitset* repeated_bits, std::vector<boost::any>* wire_values, compiler::dummy<0> dummy = 0)
323  {
324  std::vector<WireType> decoded_msgs = decode_repeated(repeated_bits);
325  wire_values->resize(decoded_msgs.size(), WireType());
326 
327  for(int i = 0, n = decoded_msgs.size(); i < n; ++i)
328  {
329  google::protobuf::Message* msg = boost::any_cast<google::protobuf::Message* >(wire_values->at(i));
330  msg->CopyFrom(decoded_msgs[i]);
331  }
332  }
333 
334  template<typename T>
335  typename boost::disable_if<boost::is_base_of<google::protobuf::Message, T>, void>::type
336  any_decode_repeated_specific(Bitset* repeated_bits, std::vector<boost::any>* wire_values, compiler::dummy<1> dummy = 0)
337  {
338  std::vector<WireType> decoded = decode_repeated(repeated_bits);
339  wire_values->resize(decoded.size(), WireType());
340 
341  for(int i = 0, n = decoded.size(); i < n; ++i)
342  wire_values->at(i) = decoded[i];
343  }
344 
345 
346  void any_pre_encode(boost::any* wire_value,
347  const boost::any& field_value)
348  {
349  try
350  {
351  if(!field_value.empty())
352  *wire_value = this->pre_encode(boost::any_cast<FieldType>(field_value));
353  }
354  catch(boost::bad_any_cast&)
355  {
356  throw(type_error("pre_encode", typeid(FieldType), field_value.type()));
357  }
358  catch(NullValueException&)
359  {
360  *wire_value = boost::any();
361  }
362  }
363 
364  void any_post_decode(const boost::any& wire_value,
365  boost::any* field_value)
366  {
367  try
368  {
369  if(!wire_value.empty())
370  *field_value = this->post_decode(boost::any_cast<WireType>(wire_value));
371  }
372  catch(boost::bad_any_cast&)
373  {
374  throw(type_error("post_decode", typeid(WireType), wire_value.type()));
375  }
376  catch(NullValueException&)
377  {
378  *field_value = boost::any();
379  }
380  }
381 
382 // void any_pre_encode_repeated(std::vector<boost::any>* wire_values,
383 // const std::vector<boost::any>& field_values);
384 
385 // void any_post_decode_repeated(const std::vector<boost::any>& wire_values,
386 // std::vector<boost::any>* field_values);
387 
388  unsigned any_size_repeated(const std::vector<boost::any>& wire_values)
389  {
390  try
391  {
392  std::vector<WireType> in;
393  for (std::vector<boost::any>::const_iterator it = wire_values.begin(); it != wire_values.end(); ++it)
394  {
395  in.push_back(boost::any_cast<WireType>(*it));
396  }
397 
398  return size_repeated(in);
399  }
400  catch(boost::bad_any_cast&)
401  { throw(type_error("size_repeated", typeid(WireType), wire_values.at(0).type())); }
402  }
403 
404 
405  };
406 
407 
408 }
409 
410 #endif
dccl::RepeatedTypedFieldCodec::encode
virtual Bitset encode(const WireType &wire_value)
Encode a non-empty field.
Definition: field_codec_typed.h:262
dccl::FieldCodecBase
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition: field_codec.h:53
dccl::RepeatedTypedFieldCodec::max_size_repeated
virtual unsigned max_size_repeated()=0
Give the max size of a repeated field.
dccl::FieldCodecBase::this_field
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
Definition: field_codec.h:80
dccl::RepeatedTypedFieldCodec::decode_repeated
virtual std::vector< WireType > decode_repeated(Bitset *bits)=0
Decode a repeated field.
dccl::TypedFieldCodec::encode
virtual Bitset encode()=0
Encode an empty field.
dccl
Dynamic Compact Control Language namespace.
Definition: gen_units_class_plugin.h:49
dccl::RepeatedTypedFieldCodec::min_size_repeated
virtual unsigned min_size_repeated()=0
Give the min size of a repeated field.
dccl::RepeatedTypedFieldCodec::decode
virtual WireType decode(dccl::Bitset *bits)
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
Definition: field_codec_typed.h:269
dccl::FieldCodecSelector
A class that goes between FieldCodecBase and TypedFieldCodec to determine if the pre_encode() and pos...
Definition: field_codec_typed.h:42
dccl::RepeatedTypedFieldCodec::max_size
virtual unsigned max_size()
Calculate maximum size of the field in bits.
Definition: field_codec_typed.h:291
dccl::RepeatedTypedFieldCodec::min_size
virtual unsigned min_size()
Calculate minimum size of the field in bits.
Definition: field_codec_typed.h:294
dccl::RepeatedTypedFieldCodec::encode_repeated
virtual Bitset encode_repeated(const std::vector< WireType > &wire_value)=0
Encode a repeated field.
dccl::RepeatedTypedFieldCodec::encode
virtual Bitset encode()
Encode an empty field.
Definition: field_codec_typed.h:255
dccl::RepeatedTypedFieldCodec::size
virtual unsigned size()
Calculate the size (in bits) of an empty field.
Definition: field_codec_typed.h:281
dccl::FieldCodecSelector::post_decode
virtual FieldType post_decode(const WireType &wire_value)=0
Convert from the WireType representation (used with encode() and decode(), i.e. "on the wire") to the...
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::RepeatedTypedFieldCodec::size
virtual unsigned size(const WireType &wire_value)
Calculate the size (in bits) of a non-empty field.
Definition: field_codec_typed.h:288
dccl::TypedFieldCodec::size
virtual unsigned size()=0
Calculate the size (in bits) of an empty field.
dccl::FieldCodecSelector::pre_encode
virtual WireType pre_encode(const FieldType &field_value)=0
Convert from the FieldType representation (used in the Google Protobuf message) to the WireType repre...
dccl::FieldCodecSelector< WireType, FieldType, typename boost::enable_if< boost::is_same< WireType, FieldType > >::type >::pre_encode
virtual WireType pre_encode(const FieldType &field_value)
No-op version of pre_encode (since FieldType == WireType)
Definition: field_codec_typed.h:67
dccl::TypedFieldCodec
Base class for static-typed (no boost::any) field encoders/decoders. Most single-valued user defined ...
Definition: field_codec_typed.h:82
Message
dccl::RepeatedTypedFieldCodec
Base class for "repeated" (multiple value) static-typed (no boost::any) field encoders/decoders....
Definition: field_codec_typed.h:228
dccl::TypedFieldCodec::decode
virtual WireType decode(Bitset *bits)=0
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
dccl::RepeatedTypedFieldCodec::size_repeated
virtual unsigned size_repeated(const std::vector< WireType > &wire_values)=0
Give the size of a repeated field.
dccl::compiler::dummy
workaround for compilers with broken template support (i.e. gcc 3.3)
Definition: field_codec_typed.h:37
dccl::FieldCodecSelector< WireType, FieldType, typename boost::enable_if< boost::is_same< WireType, FieldType > >::type >::post_decode
virtual FieldType post_decode(const WireType &wire_value)
No-op version of post_encode (since FieldType == WireType)
Definition: field_codec_typed.h:70