DCCL v3
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  protected:
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  protected:
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
Exception used to signal null (non-existent) value within field codecs during decode.
Definition: exception.h:39
virtual WireType pre_encode(const FieldType &field_value)
No-op version of pre_encode (since FieldType == WireType)
virtual unsigned size()
Calculate the size (in bits) of an empty field.
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
Definition: field_codec.h:75
virtual Bitset encode()
Encode an empty field.
virtual unsigned min_size()
Calculate minimum size of the field in bits.
Base class for "repeated" (multiple value) static-typed (no boost::any) field encoders/decoders. Use TypedFixedFieldCodec if your codec is fixed length (always uses the same number of bits on the wire). Use TypedFieldCodec if your fields are always singular ("optional" or "required"). Singular fields are default implemented in this codec by calls to the equivalent repeated function with an empty or single valued vector.
virtual unsigned size(const WireType &wire_value)
Calculate the size (in bits) of a non-empty field.
Base class for static-typed (no boost::any) field encoders/decoders. Most single-valued user defined ...
virtual unsigned max_size()
Calculate maximum size of the field in bits.
A class that goes between FieldCodecBase and TypedFieldCodec to determine if the pre_encode() and pos...
Dynamic Compact Control Language namespace.
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition: field_codec.h:47
workaround for compilers with broken template support (i.e. gcc 3.3)
virtual Bitset encode(const WireType &wire_value)
Encode a non-empty field.
virtual FieldType post_decode(const WireType &wire_value)
No-op version of post_encode (since FieldType == WireType)
virtual WireType decode(dccl::Bitset *bits)
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()), throw NullValueException to indicate this.
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy...
Definition: bitset.h:38