DCCL v4
field_codec_default.cpp
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 //
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 #include <algorithm>
26 #include <sstream>
27 
28 #include "../codec.h"
29 #include "field_codec_default.h"
30 
31 #if DCCL_THREAD_SUPPORT
32 std::mutex dccl::v2::TimeCodecClock::clock_mutex_;
33 #endif
34 
35 std::function<dccl::int64()> dccl::v2::TimeCodecClock::epoch_sec_func_;
36 
37 using namespace dccl::logger;
38 
39 //
40 // DefaultBoolCodec
41 //
42 
44 
46 {
47  return Bitset(size(), use_required() ? wire_value : wire_value + 1);
48 }
49 
51 {
52  unsigned long t = bits->to_ulong();
53  if (use_required())
54  {
55  return t;
56  }
57  else if (t)
58  {
59  --t;
60  return t;
61  }
62  else
63  {
64  throw NullValueException();
65  }
66 }
67 
69 {
70  // true and false
71  const unsigned BOOL_VALUES = 2;
72  // if field unspecified
73  const unsigned NULL_VALUE = use_required() ? 0 : 1;
74 
75  return dccl::ceil_log2(BOOL_VALUES + NULL_VALUE);
76 }
77 
79 
80 //
81 // DefaultStringCodec
82 //
83 
84 dccl::Bitset dccl::v2::DefaultStringCodec::encode() { return Bitset(min_size()); }
85 
86 dccl::Bitset dccl::v2::DefaultStringCodec::encode(const std::string& wire_value)
87 {
88  std::string s = wire_value;
89  if (s.size() > dccl_field_options().max_length())
90  {
91  if (this->strict())
92  throw(dccl::OutOfRangeException(std::string("String too long for field: ") +
93  FieldCodecBase::this_field()->DebugString(),
94  this->this_field(), this->this_descriptor()));
95 
96  dccl::dlog.is(DEBUG2) &&
97  dccl::dlog << "String " << s << " exceeds `dccl.max_length`, truncating" << std::endl;
98  s.resize(dccl_field_options().max_length());
99  }
100 
101  Bitset value_bits;
102  value_bits.from_byte_string(s);
103 
104  Bitset length_bits(min_size(), s.length());
105 
106  dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec value_bits: " << value_bits
107  << std::endl;
108 
109  dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec length_bits: " << length_bits
110  << std::endl;
111 
112  // adds to MSBs
113  for (int i = 0, n = value_bits.size(); i < n; ++i) length_bits.push_back(value_bits[i]);
114 
115  dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec created: " << length_bits
116  << std::endl;
117 
118  return length_bits;
119 }
120 
121 std::string dccl::v2::DefaultStringCodec::decode(Bitset* bits)
122 {
123  unsigned value_length = bits->to_ulong();
124 
125  if (value_length)
126  {
127  unsigned header_length = min_size();
128 
129  dccl::dlog.is(DEBUG2) && dccl::dlog << "Length of string is = " << value_length
130  << std::endl;
131 
132  dccl::dlog.is(DEBUG2) && dccl::dlog << "bits before get_more_bits " << *bits << std::endl;
133 
134  // grabs more bits to add to the MSBs of `bits`
135  bits->get_more_bits(value_length * BITS_IN_BYTE);
136 
137  dccl::dlog.is(DEBUG2) && dccl::dlog << "bits after get_more_bits " << *bits << std::endl;
138  Bitset string_body_bits = *bits;
139  string_body_bits >>= header_length;
140  string_body_bits.resize(bits->size() - header_length);
141 
142  return string_body_bits.to_byte_string();
143  }
144  else
145  {
146  throw NullValueException();
147  }
148 }
149 
150 unsigned dccl::v2::DefaultStringCodec::size() { return min_size(); }
151 
152 unsigned dccl::v2::DefaultStringCodec::size(const std::string& wire_value)
153 {
154  return std::min(min_size() + static_cast<unsigned>(wire_value.length() * BITS_IN_BYTE),
155  max_size());
156 }
157 
158 unsigned dccl::v2::DefaultStringCodec::max_size()
159 {
160  // string length + actual string
161  return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE;
162 }
163 
164 unsigned dccl::v2::DefaultStringCodec::min_size() { return dccl::ceil_log2(MAX_STRING_LENGTH + 1); }
165 
166 void dccl::v2::DefaultStringCodec::validate()
167 {
168  require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
169  require(dccl_field_options().max_length() <= MAX_STRING_LENGTH,
170  "(dccl.field).max_length must be <= " +
171  std::to_string(static_cast<int>(MAX_STRING_LENGTH)));
172 }
173 
174 //
175 // DefaultBytesCodec
176 //
178 
179 dccl::Bitset dccl::v2::DefaultBytesCodec::encode(const std::string& wire_value)
180 {
181  Bitset bits;
182  bits.from_byte_string(wire_value);
183 
184  if (bits.size() > max_size() && this->strict())
185  throw(dccl::OutOfRangeException(std::string("Bytes too long for field: ") +
186  FieldCodecBase::this_field()->DebugString(),
187  this->this_field(), this->this_descriptor()));
188 
189  bits.resize(max_size());
190 
191  if (!use_required())
192  {
193  bits <<= 1;
194  bits.set(0, true); // presence bit
195  }
196 
197  return bits;
198 }
199 
200 unsigned dccl::v2::DefaultBytesCodec::size() { return min_size(); }
201 
202 unsigned dccl::v2::DefaultBytesCodec::size(const std::string& /*wire_value*/) { return max_size(); }
203 
205 {
206  if (!use_required())
207  {
208  if (bits->to_ulong())
209  {
210  // grabs more bits to add to the MSBs of `bits`
211  bits->get_more_bits(max_size() - min_size());
212 
213  Bitset bytes_body_bits = *bits;
214  bytes_body_bits >>= min_size();
215  bytes_body_bits.resize(bits->size() - min_size());
216 
217  return bytes_body_bits.to_byte_string();
218  }
219  else
220  {
221  throw NullValueException();
222  }
223  }
224  else
225  {
226  return bits->to_byte_string();
227  }
228 }
229 
231 {
232  return dccl_field_options().max_length() * BITS_IN_BYTE +
233  (use_required() ? 0 : 1); // presence bit?
234 }
235 
237 {
238  if (use_required())
239  return max_size();
240  else
241  return 1; // presence bit
242 }
243 
245 {
246  require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
247 }
248 
249 //
250 // DefaultEnumCodec
251 //
253  const google::protobuf::EnumValueDescriptor* const& field_value)
254 {
255  return field_value->index();
256 }
257 
258 const google::protobuf::EnumValueDescriptor*
260 {
261  const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
262 
263  if (wire_value < e->value_count())
264  {
265  const google::protobuf::EnumValueDescriptor* return_value = e->value(wire_value);
266  return return_value;
267  }
268  else
269  throw NullValueException();
270 }
dccl::v2::DefaultBoolCodec::validate
void validate() override
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec_default.cpp:78
dccl::v2::DefaultBytesCodec::min_size
unsigned min_size() override
Calculate minimum size of the field in bits.
Definition: field_codec_default.cpp:236
dccl::v2::DefaultBytesCodec::max_size
unsigned max_size() override
Calculate maximum size of the field in bits.
Definition: field_codec_default.cpp:230
dccl::v2::DefaultBytesCodec::validate
void validate() override
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Definition: field_codec_default.cpp:244
dccl::v2::DefaultEnumCodec::post_decode
const google::protobuf::EnumValueDescriptor * post_decode(const int32 &wire_value) override
Convert from the WireType representation (used with encode() and decode(), i.e. "on the wire") to the...
Definition: field_codec_default.cpp:259
dccl::Bitset::to_ulong
unsigned long to_ulong() const
Returns the value of the Bitset as an unsigned long integer. Equivalent to to<unsigned long>().
Definition: bitset.h:274
dccl::Bitset::get_more_bits
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition: bitset.h:419
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::Logger::is
bool is(logger::Verbosity verbosity, logger::Group group=logger::GENERAL)
Indicates the verbosity of the Logger until the next std::flush or std::endl. The boolean return is u...
Definition: logger.h:192
dccl::v2::DefaultEnumCodec::pre_encode
int32 pre_encode(const google::protobuf::EnumValueDescriptor *const &field_value) override
Convert from the FieldType representation (used in the Google Protobuf message) to the WireType repre...
Definition: field_codec_default.cpp:252
dccl::Bitset::from_byte_string
void from_byte_string(const std::string &s)
Sets the value of the Bitset to the contents of a byte string, where each character represents 8 bits...
Definition: bitset.h:334
dccl::ceil_log2
unsigned ceil_log2(dccl::uint64 v)
Definition: binary.h:178
dccl::int64
google::protobuf::int64 int64
a signed 64 bit integer
Definition: common.h:62
dccl::v2::DefaultBoolCodec::decode
bool decode(Bitset *bits) override
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
Definition: field_codec_default.cpp:50
dccl::v2::DefaultBytesCodec::size
unsigned size() override
Calculate the size (in bits) of an empty field.
Definition: field_codec_default.cpp:200
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::OutOfRangeException
Definition: exception.h:68
dccl::v2::DefaultBoolCodec::size
unsigned size() override
The size of the encoded message in bits. Use TypedFieldCodec if the size depends on the data.
Definition: field_codec_default.cpp:68
dccl::Bitset::set
Bitset & set(size_type n, bool val=true)
Set a bit to a given value.
Definition: bitset.h:174
dccl::v2::DefaultBytesCodec::decode
std::string decode(Bitset *bits) override
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
Definition: field_codec_default.cpp:204
dccl::int32
google::protobuf::int32 int32
a signed 32 bit integer
Definition: common.h:58
dccl::v2::DefaultBytesCodec::encode
Bitset encode() override
Encode an empty field.
Definition: field_codec_default.cpp:177
dccl::v2::DefaultBoolCodec::encode
Bitset encode() override
Encode an empty field.
Definition: field_codec_default.cpp:43
dccl::Bitset::to_byte_string
std::string to_byte_string()
Returns the value of the Bitset to a byte string, where each character represents 8 bits of the Bitse...
Definition: bitset.h:296