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 using namespace dccl::logger;
32 
33 //
34 // DefaultBoolCodec
35 //
36 
37 dccl::Bitset dccl::v2::DefaultBoolCodec::encode() { return Bitset(size()); }
38 
39 dccl::Bitset dccl::v2::DefaultBoolCodec::encode(const bool& wire_value)
40 {
41  return Bitset(size(), use_required() ? wire_value : wire_value + 1);
42 }
43 
44 bool dccl::v2::DefaultBoolCodec::decode(Bitset* bits)
45 {
46  unsigned long t = bits->to_ulong();
47  if (use_required())
48  {
49  return t;
50  }
51  else if (t)
52  {
53  --t;
54  return t;
55  }
56  else
57  {
58  throw NullValueException();
59  }
60 }
61 
62 unsigned dccl::v2::DefaultBoolCodec::size()
63 {
64  // true and false
65  const unsigned BOOL_VALUES = 2;
66  // if field unspecified
67  const unsigned NULL_VALUE = use_required() ? 0 : 1;
68 
69  return dccl::ceil_log2(BOOL_VALUES + NULL_VALUE);
70 }
71 
72 void dccl::v2::DefaultBoolCodec::validate() {}
73 
74 //
75 // DefaultStringCodec
76 //
77 
78 dccl::Bitset dccl::v2::DefaultStringCodec::encode() { return Bitset(min_size()); }
79 
80 dccl::Bitset dccl::v2::DefaultStringCodec::encode(const std::string& wire_value)
81 {
82  std::string s = wire_value;
83  if (s.size() > dccl_field_options().max_length())
84  {
85  if (this->strict())
86  throw(dccl::OutOfRangeException(std::string("String too long for field: ") +
87  FieldCodecBase::this_field()->DebugString(),
88  this->this_field(), this->this_descriptor()));
89 
90  dccl::dlog.is(DEBUG2) &&
91  dccl::dlog << "String " << s << " exceeds `dccl.max_length`, truncating" << std::endl;
92  s.resize(dccl_field_options().max_length());
93  }
94 
95  Bitset value_bits;
96  value_bits.from_byte_string(s);
97 
98  Bitset length_bits(min_size(), s.length());
99 
100  dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec value_bits: " << value_bits
101  << std::endl;
102 
103  dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec length_bits: " << length_bits
104  << std::endl;
105 
106  // adds to MSBs
107  for (int i = 0, n = value_bits.size(); i < n; ++i) length_bits.push_back(value_bits[i]);
108 
109  dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec created: " << length_bits
110  << std::endl;
111 
112  return length_bits;
113 }
114 
115 std::string dccl::v2::DefaultStringCodec::decode(Bitset* bits)
116 {
117  unsigned value_length = bits->to_ulong();
118 
119  if (value_length)
120  {
121  unsigned header_length = min_size();
122 
123  dccl::dlog.is(DEBUG2) && dccl::dlog << "Length of string is = " << value_length
124  << std::endl;
125 
126  dccl::dlog.is(DEBUG2) && dccl::dlog << "bits before get_more_bits " << *bits << std::endl;
127 
128  // grabs more bits to add to the MSBs of `bits`
129  bits->get_more_bits(value_length * BITS_IN_BYTE);
130 
131  dccl::dlog.is(DEBUG2) && dccl::dlog << "bits after get_more_bits " << *bits << std::endl;
132  Bitset string_body_bits = *bits;
133  string_body_bits >>= header_length;
134  string_body_bits.resize(bits->size() - header_length);
135 
136  return string_body_bits.to_byte_string();
137  }
138  else
139  {
140  throw NullValueException();
141  }
142 }
143 
144 unsigned dccl::v2::DefaultStringCodec::size() { return min_size(); }
145 
146 unsigned dccl::v2::DefaultStringCodec::size(const std::string& wire_value)
147 {
148  return std::min(min_size() + static_cast<unsigned>(wire_value.length() * BITS_IN_BYTE),
149  max_size());
150 }
151 
152 unsigned dccl::v2::DefaultStringCodec::max_size()
153 {
154  // string length + actual string
155  return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE;
156 }
157 
158 unsigned dccl::v2::DefaultStringCodec::min_size() { return dccl::ceil_log2(MAX_STRING_LENGTH + 1); }
159 
160 void dccl::v2::DefaultStringCodec::validate()
161 {
162  require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
163  require(dccl_field_options().max_length() <= MAX_STRING_LENGTH,
164  "(dccl.field).max_length must be <= " +
165  std::to_string(static_cast<int>(MAX_STRING_LENGTH)));
166 }
167 
168 //
169 // DefaultBytesCodec
170 //
171 dccl::Bitset dccl::v2::DefaultBytesCodec::encode() { return Bitset(min_size(), 0); }
172 
173 dccl::Bitset dccl::v2::DefaultBytesCodec::encode(const std::string& wire_value)
174 {
175  Bitset bits;
176  bits.from_byte_string(wire_value);
177 
178  if (bits.size() > max_size() && this->strict())
179  throw(dccl::OutOfRangeException(std::string("Bytes too long for field: ") +
180  FieldCodecBase::this_field()->DebugString(),
181  this->this_field(), this->this_descriptor()));
182 
183  bits.resize(max_size());
184 
185  if (!use_required())
186  {
187  bits <<= 1;
188  bits.set(0, true); // presence bit
189  }
190 
191  return bits;
192 }
193 
194 unsigned dccl::v2::DefaultBytesCodec::size() { return min_size(); }
195 
196 unsigned dccl::v2::DefaultBytesCodec::size(const std::string& /*wire_value*/) { return max_size(); }
197 
198 std::string dccl::v2::DefaultBytesCodec::decode(Bitset* bits)
199 {
200  if (!use_required())
201  {
202  if (bits->to_ulong())
203  {
204  // grabs more bits to add to the MSBs of `bits`
205  bits->get_more_bits(max_size() - min_size());
206 
207  Bitset bytes_body_bits = *bits;
208  bytes_body_bits >>= min_size();
209  bytes_body_bits.resize(bits->size() - min_size());
210 
211  return bytes_body_bits.to_byte_string();
212  }
213  else
214  {
215  throw NullValueException();
216  }
217  }
218  else
219  {
220  return bits->to_byte_string();
221  }
222 }
223 
224 unsigned dccl::v2::DefaultBytesCodec::max_size()
225 {
226  return dccl_field_options().max_length() * BITS_IN_BYTE +
227  (use_required() ? 0 : 1); // presence bit?
228 }
229 
230 unsigned dccl::v2::DefaultBytesCodec::min_size()
231 {
232  if (use_required())
233  return max_size();
234  else
235  return 1; // presence bit
236 }
237 
238 void dccl::v2::DefaultBytesCodec::validate()
239 {
240  require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
241 }
242 
243 //
244 // DefaultEnumCodec
245 //
247  const google::protobuf::EnumValueDescriptor* const& field_value)
248 {
249  return field_value->index();
250 }
251 
252 const google::protobuf::EnumValueDescriptor*
254 {
255  const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
256 
257  if (wire_value < e->value_count())
258  {
259  const google::protobuf::EnumValueDescriptor* return_value = e->value(wire_value);
260  return return_value;
261  }
262  else
263  throw NullValueException();
264 }
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:253
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:597
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:191
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:246
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::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::int32
google::protobuf::int32 int32
a signed 32 bit integer
Definition: common.h:57