$darkmode
duration.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Robert Bosch GmbH
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * SPDX-License-Identifier: Apache-2.0
17  */
25 #pragma once
26 #ifndef FABLE_SCHEMA_DURATION_HPP_
27 #define FABLE_SCHEMA_DURATION_HPP_
28 
29 #include <chrono> // for duration<>
30 #include <limits> // for numeric_limits<>
31 #include <string> // for string
32 #include <utility> // for move
33 
34 #include <fable/schema/interface.hpp> // for Base<>
35 
36 namespace fable {
37 namespace schema {
38 
39 template <typename T, typename Period>
40 class Duration : public Base<Duration<T, Period>> {
41  public: // Types and Constructors
42  using Type = std::chrono::duration<T, Period>;
43 
44  template <typename X = T,
45  std::enable_if_t<std::is_integral<X>::value && std::is_unsigned<X>::value, int> = 0>
46  Duration(Type* ptr, std::string&& desc)
47  : Base<Duration<T, Period>>(JsonType::number_unsigned, std::move(desc)), ptr_(ptr) {}
48 
49  template <typename X = T,
50  std::enable_if_t<std::is_integral<X>::value && std::is_signed<X>::value, int> = 0>
51  Duration(Type* ptr, std::string&& desc)
52  : Base<Duration<T, Period>>(JsonType::number_integer, std::move(desc)), ptr_(ptr) {}
53 
54  template <typename X = T, std::enable_if_t<std::is_floating_point<X>::value, int> = 0>
55  Duration(Type* ptr, std::string&& desc)
56  : Base<Duration<T, Period>>(JsonType::number_float, std::move(desc)), ptr_(ptr) {}
57 
58  public: // Special
59  T minimum() const { return value_min_; }
60  bool exclusive_minimum() const { return exclusive_min_; }
61  Duration<T, Period> minimum(T value) && {
62  value_min_ = value;
63  exclusive_min_ = false;
64  return std::move(*this);
65  }
66  Duration<T, Period> exclusive_minimum(T value) && {
67  value_min_ = value;
68  exclusive_min_ = true;
69  return std::move(*this);
70  }
71 
72  T maximum() const { return value_max_; }
73  bool exclusive_maximum() const { return exclusive_max_; }
74  Duration<T, Period> maximum(T value) && {
75  value_max_ = value;
76  exclusive_max_ = false;
77  return std::move(*this);
78  }
79  Duration<T, Period> exclusive_maximum(T value) && {
80  value_max_ = value;
81  exclusive_max_ = true;
82  return std::move(*this);
83  }
84 
85  std::pair<T, T> bounds() const { return std::make_pair(value_min_, value_max_); }
86  Duration<T, Period> bounds(T min, T max) && {
87  exclusive_min_ = false;
88  value_min_ = min;
89  exclusive_max_ = false;
90  value_max_ = max;
91  return std::move(*this);
92  }
93 
94  public: // Overrides
95  Json json_schema() const override {
96  Json j{
97  {"type", this->type_string()},
98  {exclusive_min_ ? "exclusiveMinimum" : "minimum", value_min_},
99  {exclusive_max_ ? "exclusiveMaximum" : "maximum", value_max_},
100  };
101  this->augment_schema(j);
102  return j;
103  }
104 
105  void validate(const Conf& c) const override {
106  switch (c->type()) {
107  case JsonType::number_unsigned: {
108  check_bounds<uint64_t>(c);
109  break;
110  }
111  case JsonType::number_integer: {
112  check_bounds<int64_t>(c);
113  break;
114  }
115  case JsonType::number_float: {
116  if (this->type() != JsonType::number_float) {
117  this->throw_wrong_type(c);
118  }
119  check_bounds<double>(c);
120  break;
121  }
122 
123  default:
124  this->throw_wrong_type(c);
125  }
126  }
127 
128  using Interface::to_json;
129  void to_json(Json& j) const override {
130  assert(ptr_ != nullptr);
131  j = serialize(*ptr_);
132  }
133 
134  void from_conf(const Conf& c) override {
135  assert(ptr_ != nullptr);
136  *ptr_ = deserialize(c);
137  }
138 
139  Json serialize(const Type& x) const { return x.count(); }
140 
141  Type deserialize(const Conf& c) const { return Type(c.get<T>()); }
142 
143  void reset_ptr() override { ptr_ = nullptr; }
144 
145  private:
149  template <typename B>
150  void check_bounds(const Conf& c) const {
151  auto v = c.get<B>();
152  if (!std::numeric_limits<B>::is_signed && value_min_ < 0) {
153  // If B is unsigned and value_min_ is less than 0, there is no way
154  // that v cannot fulfill the minimum requirements. Trying to use the
155  // other branches will "underflow" the value_min_ which will invalidate
156  // any comparison.
157  } else if (exclusive_min_) {
158  if (v <= static_cast<B>(value_min_)) {
159  this->throw_error(c, "expected exclusive minimum of {}, got {}", value_min_, v);
160  }
161  } else {
162  if (v < static_cast<B>(value_min_)) {
163  this->throw_error(c, "expected minimum of {}, got {}", value_min_, v);
164  }
165  }
166 
167  if (!std::numeric_limits<B>::is_signed && value_max_ < 0) {
168  // If B is unsigned, but our maximum value is somewhere below 0, then v
169  // will by definition always be out-of-bounds.
170  this->throw_error(c, "expected {}maximum of {}, got {}", (exclusive_max_ ? "exclusive " : ""),
171  value_max_, v);
172  } else if (exclusive_max_) {
173  if (v >= static_cast<B>(value_max_)) {
174  this->throw_error(c, "expected exclusive maximum of {}, got {}", value_max_, v);
175  }
176  } else {
177  if (v > static_cast<B>(value_max_)) {
178  this->throw_error(c, "expected maximum of {}, got {}", value_max_, v);
179  }
180  }
181  }
182 
183  private:
184  bool exclusive_min_{false};
185  bool exclusive_max_{false};
186  T value_min_{std::numeric_limits<T>::lowest()};
187  T value_max_{std::numeric_limits<T>::max()};
188  Type* ptr_{nullptr};
189 };
190 
191 template <typename Rep, typename Period>
192 inline Duration<Rep, Period> make_schema(std::chrono::duration<Rep, Period>* ptr,
193  std::string&& desc) {
194  return Duration<Rep, Period>(ptr, std::move(desc));
195 }
196 
197 } // namespace schema
198 } // namespace fable
199 
200 #endif // FABLE_SCHEMA_DURATION_HPP_
Definition: conf.hpp:74
JsonType type() const override
Definition: interface.hpp:365
void reset_ptr() override
Definition: duration.hpp:143
T get() const
Definition: conf.hpp:164
nlohmann::json Json
Definition: json.hpp:62
Definition: conf.hpp:70
Definition: duration.hpp:40
virtual Json to_json() const
Definition: interface.hpp:220
void validate(const Conf &c) const override
Definition: duration.hpp:105
void from_conf(const Conf &c) override
Definition: duration.hpp:134
void to_json(Json &j) const override
Definition: duration.hpp:129
Json json_schema() const override
Definition: duration.hpp:95
Definition: interface.hpp:354
std::string type_string() const override
Definition: interface.hpp:366