DCCL v4
field_codec_typed.h
1 // Copyright 2011-2019:
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 // File authors:
6 // Toby Schneider <toby@gobysoft.org>
7 // Chris Murphy <cmurphy@aphysci.com>
8 // Kyle Guilbert <kguilbert@aphysci.com>
9 //
10 //
11 // This file is part of the Dynamic Compact Control Language Library
12 // ("DCCL").
13 //
14 // DCCL is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU Lesser General Public License as published by
16 // the Free Software Foundation, either version 2.1 of the License, or
17 // (at your option) any later version.
18 //
19 // DCCL is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU Lesser General Public License for more details.
23 //
24 // You should have received a copy of the GNU Lesser General Public License
25 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
26 #ifndef DCCLFIELDCODECTYPED20120312H
27 #define DCCLFIELDCODECTYPED20120312H
28 
29 #include <type_traits>
30 
31 #include "field_codec.h"
32 
33 namespace dccl
34 {
35 
37 template <typename WireType, typename FieldType, class Enable = void>
39 {
40  public:
45  virtual WireType pre_encode(const FieldType& field_value) = 0;
46 
51  virtual FieldType post_decode(const WireType& wire_value) = 0;
52 };
53 
55 template <typename WireType, typename FieldType>
56 class FieldCodecSelector<WireType, FieldType,
57  std::enable_if_t<std::is_same<WireType, FieldType>::value>>
58  : public FieldCodecBase
59 {
60  public:
62  virtual WireType pre_encode(const FieldType& field_value) { return field_value; }
64  virtual FieldType post_decode(const WireType& wire_value) { return wire_value; }
65 };
66 
72 template <typename WireType, typename FieldType = WireType>
73 class TypedFieldCodec : public FieldCodecSelector<WireType, FieldType>
74 {
75  public:
76  using wire_type = WireType;
77  using field_type = FieldType;
78 
79  public:
83  virtual Bitset encode() = 0;
84 
89  virtual Bitset encode(const WireType& wire_value) = 0;
90 
95  virtual WireType decode(Bitset* bits) = 0;
96 
100  virtual unsigned size() = 0;
101 
106  virtual unsigned size(const WireType& wire_value) = 0;
107 
108  private:
109  unsigned any_size(const dccl::any& wire_value) override
110  {
111  try
112  {
113  return is_empty(wire_value) ? size() : size(dccl::any_cast<WireType>(wire_value));
114  }
115  catch (dccl::bad_any_cast&)
116  {
117  throw(type_error("size", typeid(WireType), wire_value.type()));
118  }
119  }
120 
121  void any_encode(Bitset* bits, const dccl::any& wire_value) override
122  {
123  try
124  {
125  *bits = is_empty(wire_value) ? encode() : encode(dccl::any_cast<WireType>(wire_value));
126  }
127  catch (dccl::bad_any_cast&)
128  {
129  throw(type_error("encode", typeid(WireType), wire_value.type()));
130  }
131  }
132 
133  void any_decode(Bitset* bits, dccl::any* wire_value) override
134  {
135  any_decode_specific<WireType>(bits, wire_value);
136  }
137 
138  void any_pre_encode(dccl::any* wire_value, const dccl::any& field_value) override
139  {
140  try
141  {
142  if (!is_empty(field_value))
143  *wire_value = this->pre_encode(dccl::any_cast<FieldType>(field_value));
144  }
145  catch (dccl::bad_any_cast&)
146  {
147  throw(type_error("pre_encode", typeid(FieldType), field_value.type()));
148  }
149  catch (NullValueException&)
150  {
151  *wire_value = dccl::any();
152  }
153  }
154 
155  void any_post_decode(const dccl::any& wire_value, dccl::any* field_value) override
156  {
157  any_post_decode_specific<WireType>(wire_value, field_value);
158  }
159 
160  // we don't currently support type conversion (post_decode / pre_encode) of Message types
161  template <typename T>
162  typename std::enable_if_t<std::is_base_of<google::protobuf::Message, T>::value, void>
163  any_post_decode_specific(const dccl::any& wire_value, dccl::any* field_value)
164  {
165  *field_value = wire_value;
166  }
167 
168  template <typename T>
169  typename std::enable_if_t<!std::is_base_of<google::protobuf::Message, T>::value, void>
170  any_post_decode_specific(const dccl::any& wire_value, dccl::any* field_value)
171  {
172  try
173  {
174  if (!is_empty(wire_value))
175  *field_value = this->post_decode(dccl::any_cast<WireType>(wire_value));
176  }
177  catch (dccl::bad_any_cast&)
178  {
179  throw(type_error("post_decode", typeid(WireType), wire_value.type()));
180  }
181  catch (NullValueException&)
182  {
183  *field_value = dccl::any();
184  }
185  }
186 
187  template <typename T>
188  typename std::enable_if_t<std::is_base_of<google::protobuf::Message, T>::value, void>
189  any_decode_specific(Bitset* bits, dccl::any* wire_value)
190  {
191  try
192  {
193  auto* msg = dccl::any_cast<google::protobuf::Message*>(*wire_value);
194  msg->CopyFrom(decode(bits));
195  }
196  catch (NullValueException&)
197  {
199  *wire_value = dccl::any();
200  }
201  }
202 
203  template <typename T>
204  typename std::enable_if_t<!std::is_base_of<google::protobuf::Message, T>::value, void>
205  any_decode_specific(Bitset* bits, dccl::any* wire_value)
206  {
207  try
208  {
209  *wire_value = decode(bits);
210  }
211  catch (NullValueException&)
212  {
213  *wire_value = dccl::any();
214  }
215  }
216 };
217 
223 template <typename WireType, typename FieldType = WireType>
224 class RepeatedTypedFieldCodec : public TypedFieldCodec<WireType, FieldType>
225 {
226  public:
227  using wire_type = WireType;
228  using field_type = FieldType;
229 
230  public:
232  virtual Bitset encode_repeated(const std::vector<WireType>& wire_value) = 0;
233 
235  virtual std::vector<WireType> decode_repeated(Bitset* bits) = 0;
236 
238  virtual unsigned size_repeated(const std::vector<WireType>& wire_values) = 0;
239 
241  unsigned max_size_repeated() override = 0;
242 
244  unsigned min_size_repeated() override = 0;
245 
249  Bitset encode() override { return encode_repeated(std::vector<WireType>()); }
250 
255  Bitset encode(const WireType& wire_value) override
256  {
257  return encode_repeated(std::vector<WireType>(1, wire_value));
258  }
259 
264  WireType decode(dccl::Bitset* bits) override
265  {
266  std::vector<WireType> return_vec = decode_repeated(bits);
267  if (is_empty(return_vec))
268  throw dccl::NullValueException();
269  else
270  return return_vec.at(0);
271  }
272 
276  unsigned size() override { return size_repeated(std::vector<WireType>()); }
277 
282  unsigned size(const WireType& wire_value) override
283  {
284  return size_repeated(std::vector<WireType>(1, wire_value));
285  }
286 
287  unsigned max_size() override { return max_size_repeated(); }
288 
289  unsigned min_size() override { return min_size_repeated(); }
290 
291  private:
292  void any_encode_repeated(Bitset* bits, const std::vector<dccl::any>& wire_values) override
293  {
294  try
295  {
296  std::vector<WireType> in;
297  for (const auto& wire_value : wire_values)
298  { in.push_back(dccl::any_cast<WireType>(wire_value)); } *bits = encode_repeated(in);
299  }
300  catch (dccl::bad_any_cast&)
301  {
302  throw(type_error("encode_repeated", typeid(WireType), wire_values.at(0).type()));
303  }
304  }
305 
306  void any_decode_repeated(Bitset* repeated_bits, std::vector<dccl::any>* field_values) override
307  {
308  any_decode_repeated_specific<WireType>(repeated_bits, field_values);
309  }
310 
311  template <typename T>
312  typename std::enable_if_t<std::is_base_of<google::protobuf::Message, T>::value, void>
313  any_decode_repeated_specific(Bitset* repeated_bits, std::vector<dccl::any>* wire_values)
314  {
315  std::vector<WireType> decoded_msgs = decode_repeated(repeated_bits);
316  wire_values->resize(decoded_msgs.size(), WireType());
317 
318  for (int i = 0, n = decoded_msgs.size(); i < n; ++i)
319  {
320  auto* msg = dccl::any_cast<google::protobuf::Message*>(wire_values->at(i));
321  msg->CopyFrom(decoded_msgs[i]);
322  }
323  }
324 
325  template <typename T>
326  typename std::enable_if_t<!std::is_base_of<google::protobuf::Message, T>::value, void>
327  any_decode_repeated_specific(Bitset* repeated_bits, std::vector<dccl::any>* wire_values)
328  {
329  std::vector<WireType> decoded = decode_repeated(repeated_bits);
330  wire_values->resize(decoded.size(), WireType());
331 
332  for (int i = 0, n = decoded.size(); i < n; ++i) wire_values->at(i) = decoded[i];
333  }
334 
335  void any_pre_encode(dccl::any* wire_value, const dccl::any& field_value) override
336  {
337  try
338  {
339  if (!is_empty(field_value))
340  *wire_value = this->pre_encode(dccl::any_cast<FieldType>(field_value));
341  }
342  catch (dccl::bad_any_cast&)
343  {
344  throw(type_error("pre_encode", typeid(FieldType), field_value.type()));
345  }
346  catch (NullValueException&)
347  {
348  *wire_value = dccl::any();
349  }
350  }
351 
352  void any_post_decode(const dccl::any& wire_value, dccl::any* field_value) override
353  {
354  try
355  {
356  if (!is_empty(wire_value))
357  *field_value = this->post_decode(dccl::any_cast<WireType>(wire_value));
358  }
359  catch (dccl::bad_any_cast&)
360  {
361  throw(type_error("post_decode", typeid(WireType), wire_value.type()));
362  }
363  catch (NullValueException&)
364  {
365  *field_value = dccl::any();
366  }
367  }
368 
369  // void any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
370  // const std::vector<dccl::any>& field_values);
371 
372  // void any_post_decode_repeated(const std::vector<dccl::any>& wire_values,
373  // std::vector<dccl::any>* field_values);
374 
375  unsigned any_size_repeated(const std::vector<dccl::any>& wire_values) override
376  {
377  try
378  {
379  std::vector<WireType> in;
380  for (const auto& wire_value : wire_values)
381  { in.push_back(dccl::any_cast<WireType>(wire_value)); } return size_repeated(in);
382  }
383  catch (dccl::bad_any_cast&)
384  {
385  throw(type_error("size_repeated", typeid(WireType), wire_values.at(0).type()));
386  }
387  }
388 };
389 
390 } // namespace dccl
391 
392 #endif
dccl::FieldCodecBase
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition: field_codec.h:54
dccl::RepeatedTypedFieldCodec::min_size_repeated
unsigned min_size_repeated() override=0
Give the min size of a repeated field.
dccl::RepeatedTypedFieldCodec::decode_repeated
virtual std::vector< WireType > decode_repeated(Bitset *bits)=0
Decode a repeated field.
dccl::FieldCodecSelector< WireType, FieldType, std::enable_if_t< std::is_same< WireType, FieldType >::value > >::pre_encode
virtual WireType pre_encode(const FieldType &field_value)
No-op version of pre_encode (since FieldType == WireType)
Definition: field_codec_typed.h:62
dccl::RepeatedTypedFieldCodec::size
unsigned size(const WireType &wire_value) override
Calculate the size (in bits) of a non-empty field.
Definition: field_codec_typed.h:282
dccl::TypedFieldCodec::encode
virtual Bitset encode()=0
Encode an empty field.
dccl
Dynamic Compact Control Language namespace.
Definition: any.h:49
dccl::FieldCodecBase::this_field
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
Definition: field_codec.cpp:653
dccl::RepeatedTypedFieldCodec::size
unsigned size() override
Calculate the size (in bits) of an empty field.
Definition: field_codec_typed.h:276
dccl::FieldCodecSelector
A class that goes between FieldCodecBase and TypedFieldCodec to determine if the pre_encode() and pos...
Definition: field_codec_typed.h:38
dccl::RepeatedTypedFieldCodec::encode
Bitset encode() override
Encode an empty field.
Definition: field_codec_typed.h:249
dccl::RepeatedTypedFieldCodec::encode_repeated
virtual Bitset encode_repeated(const std::vector< WireType > &wire_value)=0
Encode a repeated field.
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::RepeatedTypedFieldCodec::decode
WireType decode(dccl::Bitset *bits) override
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
Definition: field_codec_typed.h:264
dccl::RepeatedTypedFieldCodec::encode
Bitset encode(const WireType &wire_value) override
Encode a non-empty field.
Definition: field_codec_typed.h:255
dccl::FieldCodecSelector< WireType, FieldType, std::enable_if_t< std::is_same< WireType, FieldType >::value > >::post_decode
virtual FieldType post_decode(const WireType &wire_value)
No-op version of post_encode (since FieldType == WireType)
Definition: field_codec_typed.h:64
dccl::NullValueException
Exception used to signal null (non-existent) value within field codecs during decode.
Definition: exception.h:62
dccl::Bitset
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition: bitset.h:41
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::RepeatedTypedFieldCodec::max_size_repeated
unsigned max_size_repeated() override=0
Give the max size of a repeated field.
dccl::TypedFieldCodec
Base class for static-typed (no dccl::any) field encoders/decoders. Most single-valued user defined v...
Definition: field_codec_typed.h:73
dccl::RepeatedTypedFieldCodec
Base class for "repeated" (multiple value) static-typed (no dccl::any) field encoders/decoders....
Definition: field_codec_typed.h:224
dccl::RepeatedTypedFieldCodec::max_size
unsigned max_size() override
Calculate maximum size of the field in bits.
Definition: field_codec_typed.h:287
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::RepeatedTypedFieldCodec::min_size
unsigned min_size() override
Calculate minimum size of the field in bits.
Definition: field_codec_typed.h:289