26
26
#define FABLE_SCHEMA_NUMBER_HPP_
27
27
28
28
#include < initializer_list> // for initializer_list<>
29
- #include < limits> // for numeric_limits<>
30
29
#include < set> // for set<>
31
30
#include < string> // for string
32
31
#include < type_traits> // for enable_if_t<>, is_arithmetic<>
33
- #include < utility> // for move
34
- #include < vector> // for vector<>
35
32
36
33
#include < fable/schema/interface.hpp> // for Base<>
37
34
@@ -45,222 +42,57 @@ class Number : public Base<Number<T>> {
45
42
public: // Types and Constructors
46
43
using Type = T;
47
44
48
- template <typename X = T,
49
- std::enable_if_t <std::is_integral<X>::value && std::is_unsigned<X>::value, int > = 0 >
45
+ template <typename X = T, std::enable_if_t <std::is_integral<X>::value && std::is_unsigned<X>::value, int > = 0 >
50
46
Number (Type* ptr, std::string&& desc)
51
47
: Base<Number<T>>(JsonType::number_unsigned, std::move(desc)), ptr_(ptr) {}
52
48
53
- template <typename X = T,
54
- std::enable_if_t <std::is_integral<X>::value && std::is_signed<X>::value, int > = 0 >
49
+ template <typename X = T, std::enable_if_t <std::is_integral<X>::value && std::is_signed<X>::value, int > = 0 >
55
50
Number (Type* ptr, std::string&& desc)
56
51
: Base<Number<T>>(JsonType::number_integer, std::move(desc)), ptr_(ptr) {}
57
52
58
53
template <typename X = T, std::enable_if_t <std::is_floating_point<X>::value, int > = 0 >
59
54
Number (Type* ptr, std::string&& desc)
60
55
: Base<Number<T>>(JsonType::number_float, std::move(desc)), ptr_(ptr) {}
61
56
57
+
62
58
public: // Special
63
59
T minimum () const { return value_min_; }
64
60
bool exclusive_minimum () const { return exclusive_min_; }
65
- Number<T> minimum (T value) && {
66
- value_min_ = value;
67
- exclusive_min_ = false ;
68
- return std::move (*this );
69
- }
70
- Number<T> exclusive_minimum (T value) && {
71
- value_min_ = value;
72
- exclusive_min_ = true ;
73
- return std::move (*this );
74
- }
61
+ Number<T> minimum (T value) &&;
62
+ Number<T> exclusive_minimum (T value) &&;
75
63
76
64
T maximum () const { return value_max_; }
77
65
bool exclusive_maximum () const { return exclusive_max_; }
78
- Number<T> maximum (T value) && {
79
- value_max_ = value;
80
- exclusive_max_ = false ;
81
- return std::move (*this );
82
- }
83
- Number<T> exclusive_maximum (T value) && {
84
- value_max_ = value;
85
- exclusive_max_ = true ;
86
- return std::move (*this );
87
- }
66
+ Number<T> maximum (T value) &&;
67
+ Number<T> exclusive_maximum (T value) &&;
88
68
89
- std::pair<T, T> bounds () const { return std::make_pair (value_min_, value_max_); }
90
- Number<T> bounds (T min, T max) && {
91
- exclusive_min_ = false ;
92
- value_min_ = min;
93
- exclusive_max_ = false ;
94
- value_max_ = max;
95
- return std::move (*this );
96
- }
97
- Number<T> bounds_with (T min, T max, std::initializer_list<T> whitelisted) {
98
- exclusive_min_ = false ;
99
- value_min_ = min;
100
- exclusive_max_ = false ;
101
- value_max_ = max;
102
- for (auto x : whitelisted) {
103
- insert_whitelist (x);
104
- }
105
- return std::move (*this );
106
- }
69
+ std::pair<T, T> bounds () const ;
70
+ Number<T> bounds (T min, T max) &&;
71
+ Number<T> bounds_with (T min, T max, std::initializer_list<T> whitelisted) &&;
107
72
108
73
const std::set<T>& whitelist () const { return whitelist_; }
109
- Number<T> whitelist (T x) && {
110
- insert_whitelist (x);
111
- return std::move (*this );
112
- }
113
- Number<T> whitelist (std::initializer_list<T> xs) && {
114
- for (auto x : xs) {
115
- insert_whitelist (x);
116
- }
117
- return std::move (*this );
118
- }
119
- void insert_whitelist (T x) {
120
- if (std::is_floating_point<T>::value) {
121
- throw std::logic_error (" cannot whitelist floating-point numbers" );
122
- }
123
- if (blacklist_.count (x)) {
124
- throw std::logic_error (" cannot add blacklisted value to whitelist: " + std::to_string (x));
125
- }
126
- whitelist_.insert (x);
127
- }
74
+ Number<T> whitelist (T x) &&;
75
+ Number<T> whitelist (std::initializer_list<T> xs) &&;
76
+ void insert_whitelist (T x);
128
77
129
78
const std::set<T>& blacklist () const { return blacklist_; }
130
- Number<T> blacklist (T x) && {
131
- insert_blacklist (x);
132
- return std::move (*this );
133
- }
134
- Number<T> blacklist (std::initializer_list<T> xs) && {
135
- for (auto x : xs) {
136
- insert_blacklist (x);
137
- }
138
- return std::move (*this );
139
- }
140
- void insert_blacklist (T x) {
141
- if (std::is_floating_point<T>::value) {
142
- throw std::logic_error (" cannot blacklist floating-point numbers" );
143
- }
144
- if (blacklist_.count (x)) {
145
- throw std::logic_error (" cannot add whitelisted value to blacklist: " + std::to_string (x));
146
- }
147
- blacklist_.insert (x);
148
- }
79
+ Number<T> blacklist (T x) &&;
80
+ Number<T> blacklist (std::initializer_list<T> xs) &&;
81
+ void insert_blacklist (T x);
149
82
150
83
public: // Overrides
151
- Json json_schema () const override {
152
- Json j{
153
- {" type" , this ->type_string ()},
154
- {exclusive_min_ ? " exclusiveMinimum" : " minimum" , value_min_},
155
- {exclusive_max_ ? " exclusiveMaximum" : " maximum" , value_max_},
156
- };
157
-
158
- if (!std::is_floating_point<T>::value) {
159
- auto write_list = [&j](auto name, auto xlist) {
160
- if (!xlist.empty ()) {
161
- std::vector<T> xs;
162
- for (auto x : xlist) {
163
- xs.emplace_back (x);
164
- }
165
- j[name] = xs;
166
- }
167
- };
168
-
169
- write_list (" whitelist" , whitelist_);
170
- write_list (" blacklist" , blacklist_);
171
- }
172
-
173
- this ->augment_schema (j);
174
- return j;
175
- }
176
-
177
- void validate (const Conf& c) const override {
178
- switch (c->type ()) {
179
- case JsonType::number_unsigned: {
180
- check_bounds<uint64_t >(c);
181
- break ;
182
- }
183
- case JsonType::number_integer: {
184
- check_bounds<int64_t >(c);
185
- break ;
186
- }
187
- case JsonType::number_float: {
188
- if (this ->type () != JsonType::number_float) {
189
- this ->throw_wrong_type (c);
190
- }
191
- check_bounds<double >(c);
192
- break ;
193
- }
194
- default :
195
- this ->throw_wrong_type (c);
196
- }
197
- }
198
-
84
+ Json json_schema () const override ;
85
+ void validate (const Conf& c) const override ;
199
86
using Interface::to_json;
200
- void to_json (Json& j) const override {
201
- assert (ptr_ != nullptr );
202
- j = serialize (*ptr_);
203
- }
204
-
205
- void from_conf (const Conf& c) override {
206
- assert (ptr_ != nullptr );
207
- *ptr_ = deserialize (c);
208
- }
209
-
210
- Json serialize (const Type& x) const { return x; }
211
-
212
- Type deserialize (const Conf& c) const { return c.get <Type>(); }
213
-
214
- void reset_ptr () override { ptr_ = nullptr ; }
87
+ void to_json (Json& j) const override ;
88
+ void from_conf (const Conf& c) override ;
89
+ Json serialize (const Type& x) const ;
90
+ Type deserialize (const Conf& c) const ;
91
+ void reset_ptr () override ;
215
92
216
93
private:
217
- /* *
218
- * Check that the min and max bounds are held by c.
219
- */
220
94
template <typename B>
221
- void check_bounds (const Conf& c) const {
222
- auto v = c.get <B>();
223
-
224
- // Check whitelist and blacklist first.
225
- if (!std::is_floating_point<T>::value) {
226
- if (whitelist_.count (v)) {
227
- return ;
228
- }
229
- if (blacklist_.count (v)) {
230
- this ->throw_error (c, " unexpected blacklisted value {}" , v);
231
- }
232
- }
233
-
234
- if (!std::numeric_limits<B>::is_signed && value_min_ < 0 ) {
235
- // If B is unsigned and value_min_ is less than 0, there is no way
236
- // that v cannot fulfill the minimum requirements. Trying to use the
237
- // other branches will "underflow" the value_min_ which will invalidate
238
- // any comparison.
239
- } else if (exclusive_min_) {
240
- if (v <= static_cast <B>(value_min_)) {
241
- this ->throw_error (c, " expected exclusive minimum of {}, got {}" , value_min_, v);
242
- }
243
- } else {
244
- if (v < static_cast <B>(value_min_)) {
245
- this ->throw_error (c, " expected minimum of {}, got {}" , value_min_, v);
246
- }
247
- }
248
-
249
- if (!std::numeric_limits<B>::is_signed && value_max_ < 0 ) {
250
- // If B is unsigned, but our maximum value is somewhere below 0, then v
251
- // will by definition always be out-of-bounds.
252
- this ->throw_error (c, " expected {}maximum of {}, got {}" , (exclusive_max_ ? " exclusive " : " " ),
253
- value_max_, v);
254
- } else if (exclusive_max_) {
255
- if (v >= static_cast <B>(value_max_)) {
256
- this ->throw_error (c, " expected exclusive maximum of {}, got {}" , value_max_, v);
257
- }
258
- } else {
259
- if (v > static_cast <B>(value_max_)) {
260
- this ->throw_error (c, " expected maximum of {}, got {}" , value_max_, v);
261
- }
262
- }
263
- }
95
+ void check_bounds (const Conf& c) const ;
264
96
265
97
private:
266
98
bool exclusive_min_{false };
0 commit comments