DCCL v4
Loading...
Searching...
No Matches
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
32namespace dccl
33{
34
36template <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
54template <typename WireType, typename FieldType>
55class 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
71template <typename WireType, typename FieldType = WireType>
72class 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
222template <typename WireType, typename FieldType = WireType>
223class 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))
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
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition bitset.h:43
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
Definition field_codec.h:54
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
virtual WireType pre_encode(const FieldType &field_value)
No-op version of pre_encode (since FieldType == WireType)
virtual FieldType post_decode(const WireType &wire_value)
No-op version of post_encode (since FieldType == WireType)
A class that goes between FieldCodecBase and TypedFieldCodec to determine if the pre_encode() and pos...
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...
virtual WireType pre_encode(const FieldType &field_value)=0
Convert from the FieldType representation (used in the Google Protobuf message) to the WireType repre...
Exception used to signal null (non-existent) value within field codecs during decode.
Definition exception.h:62
Base class for "repeated" (multiple value) static-typed (no dccl::any) field encoders/decoders....
unsigned max_size() override
Calculate maximum size of the field in bits.
virtual std::vector< WireType > decode_repeated(Bitset *bits)=0
Decode a repeated field.
virtual Bitset encode_repeated(const std::vector< WireType > &wire_value)=0
Encode a repeated field.
WireType decode(dccl::Bitset *bits) override
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
unsigned max_size_repeated() override=0
Give the max size of a repeated field.
virtual unsigned size_repeated(const std::vector< WireType > &wire_values)=0
Give the size of a repeated field.
Bitset encode() override
Encode an empty field.
unsigned min_size() override
Calculate minimum size of the field in bits.
Bitset encode(const WireType &wire_value) override
Encode a non-empty field.
unsigned size() override
Calculate the size (in bits) of an empty field.
unsigned min_size_repeated() override=0
Give the min size of a repeated field.
unsigned size(const WireType &wire_value) override
Calculate the size (in bits) of a non-empty field.
Base class for static-typed (no dccl::any) field encoders/decoders. Most single-valued user defined v...
virtual Bitset encode()=0
Encode an empty field.
virtual unsigned size(const WireType &wire_value)=0
Calculate the size (in bits) of a non-empty field.
virtual unsigned size()=0
Calculate the size (in bits) of an empty field.
virtual WireType decode(Bitset *bits)=0
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
virtual Bitset encode(const WireType &wire_value)=0
Encode a non-empty field.
Dynamic Compact Control Language namespace.
Definition any.h:47