27 #ifndef DCCLFIELDCODECDEFAULT20110322H
28 #define DCCLFIELDCODECDEFAULT20110322H
32 #include <google/protobuf/descriptor.h>
34 #include "dccl/option_extensions.pb.h"
36 #include "../binary.h"
37 #include "../field_codec.h"
38 #include "../field_codec_fixed.h"
39 #include "../thread_safety.h"
40 #include "field_codec_default_message.h"
50 template <
typename WireType,
typename FieldType = WireType>
61 dc.regenerate(this->this_message(), this->root_message());
77 dc.regenerate(this->this_message(), this->root_message());
90 virtual double resolution()
93 return std::pow(10.0, -precision());
101 "missing (dccl.field).min");
103 "missing (dccl.field).max");
106 "(dccl.field).resolution must be greater than 0");
110 "at most one of either (dccl.field).precision or (dccl.field).resolution can be set");
112 validate_numeric_bounds();
115 void validate_numeric_bounds()
119 std::numeric_limits<WireType>::lowest(),
120 "(dccl.field).min must be >= minimum of this field type.");
122 std::numeric_limits<WireType>::max(),
123 "(dccl.field).max must be <= maximum of this field type.");
126 const double min_max_eps = 1e-10;
127 bool min_multiple_of_res = std::abs(quantize(min(), resolution()) - min()) < min_max_eps;
128 bool max_multiple_of_res = std::abs(quantize(max(), resolution()) - max()) < min_max_eps;
134 "(dccl.field).min must be an exact multiple of (dccl.field).resolution");
137 "(dccl.field).max must be an exact multiple of (dccl.field).resolution");
141 auto res = resolution();
143 if (!min_multiple_of_res)
144 dccl::dlog.
is(dccl::logger::WARN, dccl::logger::GENERAL) &&
145 dccl::dlog <<
"Warning: (dccl.field).min should be an exact multiple of "
146 "10^(-(dccl.field).precision), i.e. "
147 << res <<
": " << this->
this_field()->DebugString() << std::endl;
148 if (!max_multiple_of_res)
149 dccl::dlog.
is(dccl::logger::WARN, dccl::logger::GENERAL) &&
150 dccl::dlog <<
"Warning: (dccl.field).max should be an exact multiple of "
151 "10^(-(dccl.field).precision), i.e. "
152 << res <<
": " << this->
this_field()->DebugString() << std::endl;
157 std::numeric_limits<double>::digits,
158 "[(dccl.field).max-(dccl.field).min]/(dccl.field).resolution must "
159 "fit in a double-precision floating point value. Please increase "
160 "min, decrease max, or decrease precision.");
167 dccl::dlog.
is(dccl::logger::DEBUG2, dccl::logger::ENCODE) &&
168 dlog <<
"Encode " << value <<
" with bounds: [" << min() <<
"," << max() <<
"]"
172 double res = resolution();
173 WireType wire_value = dccl::quantize(value, res);
176 if (wire_value < min() || wire_value > max())
181 std::string(
"Value exceeds min/max bounds for field: ") +
190 wire_value -= dccl::quantize(
static_cast<WireType
>(min()), res);
194 wire_value *= (1.0 / res);
195 auto uint_value =
static_cast<dccl::uint64>(dccl::round(wire_value, 0));
208 dccl::dlog.
is(dccl::logger::DEBUG2, dccl::logger::DECODE) &&
209 dlog <<
"Decode with bounds: [" << min() <<
"," << max() <<
"]" << std::endl;
215 dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
224 auto wire_value = (WireType)uint_value;
225 double res = resolution();
229 wire_value /= (1.0 / res);
234 dccl::quantize(wire_value + dccl::quantize(
static_cast<WireType
>(min()), res), res);
246 return dccl::ceil_log2((max() - min()) / resolution() + 1 + NULL_VALUE);
259 unsigned size()
override;
260 unsigned size(
const bool& wire_value)
override {
return size(); }
271 Bitset encode(
const std::string& wire_value)
override;
272 std::string decode(
Bitset* bits)
override;
273 unsigned size()
override;
274 unsigned size(
const std::string& wire_value)
override;
275 unsigned max_size()
override;
276 unsigned min_size()
override;
277 void validate()
override;
282 MAX_STRING_LENGTH = 255
293 unsigned size()
override;
294 unsigned size(
const std::string& wire_value)
override;
305 int32 pre_encode(
const google::protobuf::EnumValueDescriptor*
const& field_value)
override;
306 const google::protobuf::EnumValueDescriptor*
post_decode(
const int32& wire_value)
override;
309 void validate()
override {}
310 std::size_t hash()
override
312 return std::hash<std::string>{}(
this_field()->enum_type()->DebugString());
315 double max()
override
317 const google::protobuf::EnumDescriptor* e =
this_field()->enum_type();
318 return e->value_count() - 1;
320 double min()
override {
return 0; }
329 if (!this->has_clock())
330 this->set_clock<std::chrono::system_clock>();
333 template <
typename Clock>
static void set_clock()
335 #if DCCL_THREAD_SUPPORT
336 const std::lock_guard<std::mutex> lock(clock_mutex_);
339 epoch_sec_func_ = []() ->
int64
341 typename Clock::time_point now = Clock::now();
342 std::chrono::seconds sec =
343 std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
347 static bool has_clock()
349 #if DCCL_THREAD_SUPPORT
350 const std::lock_guard<std::mutex> lock(clock_mutex_);
352 return epoch_sec_func_ ? true :
false;
356 static int64 epoch_sec()
358 #if DCCL_THREAD_SUPPORT
359 const std::lock_guard<std::mutex> lock(clock_mutex_);
361 return epoch_sec_func_();
365 #if DCCL_THREAD_SUPPORT
366 static std::mutex clock_mutex_;
368 static std::function<
int64()> epoch_sec_func_;
371 typedef double time_wire_type;
375 template <
typename TimeType,
int conversion_factor>
382 time_wire_type
pre_encode(
const TimeType& time_of_day)
override
384 time_wire_type max_secs = max();
385 return std::fmod(time_of_day /
static_cast<time_wire_type
>(conversion_factor), max_secs);
388 TimeType post_decode(
const time_wire_type& encoded_time)
override
390 auto max_secs =
static_cast<int64>(max());
391 int64_t now_secs = this->epoch_sec();
392 int64 daystart = now_secs - (now_secs % max_secs);
393 int64 today_time = now_secs - daystart;
396 if ((encoded_time - today_time) > (max_secs / 2))
397 daystart -= max_secs;
398 else if ((today_time - encoded_time) > (max_secs / 2))
399 daystart += max_secs;
401 return dccl::round((TimeType)(conversion_factor * (daystart + encoded_time)),
402 precision() - std::log10((
double)conversion_factor));
406 void validate()
override
408 DefaultNumericFieldCodec<time_wire_type, TimeType>::validate_numeric_bounds();
411 double max()
override
416 double min()
override {
return 0; }
417 double precision()
override
424 (double)std::log10((
double)conversion_factor);
431 SECONDS_IN_DAY = 86400
437 static_assert(
sizeof(
TimeCodec) == 0,
"Must use specialization of TimeCodec");
453 Bitset encode(
const T&)
override {
return Bitset(size()); }
457 T decode(
Bitset* )
override
465 unsigned size()
override {
return 0; }
467 void validate()
override
470 "missing (dccl.field).static_value");
473 std::istringstream iss(t);