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