/src/valijson/include/valijson/constraints/concrete_constraints.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * |
4 | | * @brief Class definitions to support JSON Schema constraints |
5 | | * |
6 | | * This file contains class definitions for all of the constraints required to |
7 | | * support JSON Schema. These classes all inherit from the BasicConstraint |
8 | | * template class, which implements the common parts of the Constraint |
9 | | * interface. |
10 | | * |
11 | | * @see BasicConstraint |
12 | | * @see Constraint |
13 | | */ |
14 | | |
15 | | #pragma once |
16 | | |
17 | | #include <limits> |
18 | | #include <map> |
19 | | #include <set> |
20 | | #include <string> |
21 | | #include <vector> |
22 | | |
23 | | #include <valijson/constraints/basic_constraint.hpp> |
24 | | #include <valijson/internal/custom_allocator.hpp> |
25 | | #include <valijson/internal/frozen_value.hpp> |
26 | | #include <valijson/schema.hpp> |
27 | | #include <valijson/exceptions.hpp> |
28 | | |
29 | | #ifdef _MSC_VER |
30 | | #pragma warning( push ) |
31 | | #pragma warning( disable : 4702 ) |
32 | | #endif |
33 | | |
34 | | namespace valijson { |
35 | | |
36 | | class ValidationResults; |
37 | | |
38 | | namespace constraints { |
39 | | |
40 | | /** |
41 | | * @brief Represents an 'allOf' constraint. |
42 | | * |
43 | | * An allOf constraint provides a collection of sub-schemas that a value must |
44 | | * validate against. If a value fails to validate against any of these sub- |
45 | | * schemas, then validation fails. |
46 | | */ |
47 | | class AllOfConstraint: public BasicConstraint<AllOfConstraint> |
48 | | { |
49 | | public: |
50 | | AllOfConstraint() |
51 | 0 | : m_subschemas(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
52 | | |
53 | | AllOfConstraint(CustomAlloc allocFn, CustomFree freeFn) |
54 | | : BasicConstraint(allocFn, freeFn), |
55 | 0 | m_subschemas(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
56 | | |
57 | | void addSubschema(const Subschema *subschema) |
58 | 0 | { |
59 | 0 | m_subschemas.push_back(subschema); |
60 | 0 | } |
61 | | |
62 | | template<typename FunctorType> |
63 | | void applyToSubschemas(const FunctorType &fn) const |
64 | | { |
65 | | unsigned int index = 0; |
66 | | for (const Subschema *subschema : m_subschemas) { |
67 | | if (!fn(index, subschema)) { |
68 | | return; |
69 | | } |
70 | | |
71 | | index++; |
72 | | } |
73 | | } |
74 | | |
75 | | private: |
76 | | typedef std::vector<const Subschema *, internal::CustomAllocator<const Subschema *>> Subschemas; |
77 | | |
78 | | /// Collection of sub-schemas, all of which must be satisfied |
79 | | Subschemas m_subschemas; |
80 | | }; |
81 | | |
82 | | /** |
83 | | * @brief Represents an 'anyOf' constraint |
84 | | * |
85 | | * An anyOf constraint provides a collection of sub-schemas that a value can |
86 | | * validate against. If a value validates against one of these sub-schemas, |
87 | | * then the validation passes. |
88 | | */ |
89 | | class AnyOfConstraint: public BasicConstraint<AnyOfConstraint> |
90 | | { |
91 | | public: |
92 | | AnyOfConstraint() |
93 | 0 | : m_subschemas(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
94 | | |
95 | | AnyOfConstraint(CustomAlloc allocFn, CustomFree freeFn) |
96 | | : BasicConstraint(allocFn, freeFn), |
97 | 0 | m_subschemas(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
98 | | |
99 | | void addSubschema(const Subschema *subschema) |
100 | 0 | { |
101 | 0 | m_subschemas.push_back(subschema); |
102 | 0 | } |
103 | | |
104 | | template<typename FunctorType> |
105 | | void applyToSubschemas(const FunctorType &fn) const |
106 | | { |
107 | | unsigned int index = 0; |
108 | | for (const Subschema *subschema : m_subschemas) { |
109 | | if (!fn(index, subschema)) { |
110 | | return; |
111 | | } |
112 | | |
113 | | index++; |
114 | | } |
115 | | } |
116 | | |
117 | | private: |
118 | | typedef std::vector<const Subschema *, internal::CustomAllocator<const Subschema *>> Subschemas; |
119 | | |
120 | | /// Collection of sub-schemas, at least one of which must be satisfied |
121 | | Subschemas m_subschemas; |
122 | | }; |
123 | | |
124 | | /** |
125 | | * @brief Represents a combination 'if', 'then' and 'else' constraints |
126 | | * |
127 | | * The schema provided by an 'if' constraint is used as the expression for a conditional. When the |
128 | | * target validates against that schema, the 'then' subschema will be also be tested. Otherwise, |
129 | | * the 'else' subschema will be tested. |
130 | | */ |
131 | | class ConditionalConstraint: public BasicConstraint<ConditionalConstraint> |
132 | | { |
133 | | public: |
134 | | ConditionalConstraint() |
135 | | : m_ifSubschema(nullptr), |
136 | | m_thenSubschema(nullptr), |
137 | 0 | m_elseSubschema(nullptr) { } |
138 | | |
139 | | ConditionalConstraint(CustomAlloc allocFn, CustomFree freeFn) |
140 | | : BasicConstraint(allocFn, freeFn), |
141 | | m_ifSubschema(nullptr), |
142 | | m_thenSubschema(nullptr), |
143 | 0 | m_elseSubschema(nullptr) { } |
144 | | |
145 | | const Subschema * getIfSubschema() const |
146 | 0 | { |
147 | 0 | return m_ifSubschema; |
148 | 0 | } |
149 | | |
150 | | const Subschema * getThenSubschema() const |
151 | 0 | { |
152 | 0 | return m_thenSubschema; |
153 | 0 | } |
154 | | |
155 | | const Subschema * getElseSubschema() const |
156 | 0 | { |
157 | 0 | return m_elseSubschema; |
158 | 0 | } |
159 | | |
160 | | void setIfSubschema(const Subschema *subschema) |
161 | 0 | { |
162 | 0 | m_ifSubschema = subschema; |
163 | 0 | } |
164 | | |
165 | | void setThenSubschema(const Subschema *subschema) |
166 | 0 | { |
167 | 0 | m_thenSubschema = subschema; |
168 | 0 | } |
169 | | |
170 | | void setElseSubschema(const Subschema *subschema) |
171 | 0 | { |
172 | 0 | m_elseSubschema = subschema; |
173 | 0 | } |
174 | | |
175 | | private: |
176 | | const Subschema *m_ifSubschema; |
177 | | const Subschema *m_thenSubschema; |
178 | | const Subschema *m_elseSubschema; |
179 | | }; |
180 | | |
181 | | class ConstConstraint: public BasicConstraint<ConstConstraint> |
182 | | { |
183 | | public: |
184 | | ConstConstraint() |
185 | 0 | : m_value(nullptr) { } |
186 | | |
187 | | ConstConstraint(CustomAlloc allocFn, CustomFree freeFn) |
188 | | : BasicConstraint(allocFn, freeFn), |
189 | 0 | m_value(nullptr) { } |
190 | | |
191 | | ConstConstraint(const ConstConstraint &other) |
192 | | : BasicConstraint(other), |
193 | 0 | m_value(other.m_value->clone()) { } |
194 | | |
195 | | adapters::FrozenValue * getValue() const |
196 | 0 | { |
197 | 0 | return m_value.get(); |
198 | 0 | } |
199 | | |
200 | | void setValue(const adapters::Adapter &value) |
201 | 0 | { |
202 | 0 | m_value = std::unique_ptr<adapters::FrozenValue>(value.freeze()); |
203 | 0 | } |
204 | | |
205 | | private: |
206 | | std::unique_ptr<adapters::FrozenValue> m_value; |
207 | | }; |
208 | | |
209 | | /** |
210 | | * @brief Represents a 'contains' constraint |
211 | | * |
212 | | * A 'contains' constraint specifies a schema that must be satisfied by at least one |
213 | | * of the values in an array. |
214 | | */ |
215 | | class ContainsConstraint: public BasicConstraint<ContainsConstraint> |
216 | | { |
217 | | public: |
218 | | ContainsConstraint() |
219 | 0 | : m_subschema(nullptr) { } |
220 | | |
221 | | ContainsConstraint(CustomAlloc allocFn, CustomFree freeFn) |
222 | | : BasicConstraint(allocFn, freeFn), |
223 | 0 | m_subschema(nullptr) { } |
224 | | |
225 | | const Subschema * getSubschema() const |
226 | 0 | { |
227 | 0 | return m_subschema; |
228 | 0 | } |
229 | | |
230 | | void setSubschema(const Subschema *subschema) |
231 | 0 | { |
232 | 0 | m_subschema = subschema; |
233 | 0 | } |
234 | | |
235 | | private: |
236 | | const Subschema *m_subschema; |
237 | | }; |
238 | | |
239 | | /** |
240 | | * @brief Represents a 'dependencies' constraint. |
241 | | * |
242 | | * A dependency constraint ensures that a given property is valid only if the |
243 | | * properties that it depends on are present. |
244 | | */ |
245 | | class DependenciesConstraint: public BasicConstraint<DependenciesConstraint> |
246 | | { |
247 | | public: |
248 | | DependenciesConstraint() |
249 | | : m_propertyDependencies(std::less<String>(), m_allocator), |
250 | | m_schemaDependencies(std::less<String>(), m_allocator) |
251 | 0 | { } |
252 | | |
253 | | DependenciesConstraint(CustomAlloc allocFn, CustomFree freeFn) |
254 | | : BasicConstraint(allocFn, freeFn), |
255 | | m_propertyDependencies(std::less<String>(), m_allocator), |
256 | | m_schemaDependencies(std::less<String>(), m_allocator) |
257 | 0 | { } |
258 | | |
259 | | template<typename StringType> |
260 | | DependenciesConstraint & addPropertyDependency( |
261 | | const StringType &propertyName, |
262 | | const StringType &dependencyName) |
263 | 0 | { |
264 | 0 | const String key(propertyName.c_str(), m_allocator); |
265 | 0 | auto itr = m_propertyDependencies.find(key); |
266 | 0 | if (itr == m_propertyDependencies.end()) { |
267 | 0 | itr = m_propertyDependencies.insert(PropertyDependencies::value_type( |
268 | 0 | key, PropertySet(std::less<String>(), m_allocator))).first; |
269 | 0 | } |
270 | |
|
271 | 0 | itr->second.insert(String(dependencyName.c_str(), m_allocator)); |
272 | |
|
273 | 0 | return *this; |
274 | 0 | } |
275 | | |
276 | | template<typename StringType, typename ContainerType> |
277 | | DependenciesConstraint & addPropertyDependencies( |
278 | | const StringType &propertyName, |
279 | | const ContainerType &dependencyNames) |
280 | 0 | { |
281 | 0 | const String key(propertyName.c_str(), m_allocator); |
282 | 0 | auto itr = m_propertyDependencies.find(key); |
283 | 0 | if (itr == m_propertyDependencies.end()) { |
284 | 0 | itr = m_propertyDependencies.insert(PropertyDependencies::value_type( |
285 | 0 | key, PropertySet(std::less<String>(), m_allocator))).first; |
286 | 0 | } |
287 | |
|
288 | 0 | typedef typename ContainerType::value_type ValueType; |
289 | 0 | for (const ValueType &dependencyName : dependencyNames) { |
290 | 0 | itr->second.insert(String(dependencyName.c_str(), m_allocator)); |
291 | 0 | } |
292 | |
|
293 | 0 | return *this; |
294 | 0 | } |
295 | | |
296 | | template<typename StringType> |
297 | | DependenciesConstraint & addSchemaDependency(const StringType &propertyName, const Subschema *schemaDependency) |
298 | 0 | { |
299 | 0 | if (m_schemaDependencies.insert(SchemaDependencies::value_type( |
300 | 0 | String(propertyName.c_str(), m_allocator), |
301 | 0 | schemaDependency)).second) { |
302 | 0 | return *this; |
303 | 0 | } |
304 | | |
305 | 0 | throwRuntimeError("Dependencies constraint already contains a dependent " |
306 | 0 | "schema for the property '" + propertyName + "'"); |
307 | 0 | } |
308 | | |
309 | | template<typename FunctorType> |
310 | | void applyToPropertyDependencies(const FunctorType &fn) const |
311 | | { |
312 | | for (const PropertyDependencies::value_type &v : m_propertyDependencies) { |
313 | | if (!fn(v.first, v.second)) { |
314 | | return; |
315 | | } |
316 | | } |
317 | | } |
318 | | |
319 | | template<typename FunctorType> |
320 | | void applyToSchemaDependencies(const FunctorType &fn) const |
321 | | { |
322 | | for (const SchemaDependencies::value_type &v : m_schemaDependencies) { |
323 | | if (!fn(v.first, v.second)) { |
324 | | return; |
325 | | } |
326 | | } |
327 | | } |
328 | | |
329 | | private: |
330 | | typedef std::set<String, std::less<String>, internal::CustomAllocator<String>> PropertySet; |
331 | | |
332 | | typedef std::map<String, PropertySet, std::less<String>, |
333 | | internal::CustomAllocator<std::pair<const String, PropertySet>>> PropertyDependencies; |
334 | | |
335 | | typedef std::map<String, const Subschema *, std::less<String>, |
336 | | internal::CustomAllocator<std::pair<const String, const Subschema *>>> SchemaDependencies; |
337 | | |
338 | | /// Mapping from property names to their property-based dependencies |
339 | | PropertyDependencies m_propertyDependencies; |
340 | | |
341 | | /// Mapping from property names to their schema-based dependencies |
342 | | SchemaDependencies m_schemaDependencies; |
343 | | }; |
344 | | |
345 | | /** |
346 | | * @brief Represents an 'enum' constraint |
347 | | * |
348 | | * An enum constraint provides a collection of permissible values for a JSON |
349 | | * node. The node will only validate against this constraint if it matches one |
350 | | * or more of the values in the collection. |
351 | | */ |
352 | | class EnumConstraint: public BasicConstraint<EnumConstraint> |
353 | | { |
354 | | public: |
355 | | EnumConstraint() |
356 | 0 | : m_enumValues(Allocator::rebind<const EnumValue *>::other(m_allocator)) { } |
357 | | |
358 | | EnumConstraint(CustomAlloc allocFn, CustomFree freeFn) |
359 | | : BasicConstraint(allocFn, freeFn), |
360 | 0 | m_enumValues(Allocator::rebind<const EnumValue *>::other(m_allocator)) { } |
361 | | |
362 | | EnumConstraint(const EnumConstraint &other) |
363 | | : BasicConstraint(other), |
364 | | m_enumValues(Allocator::rebind<const EnumValue *>::other(m_allocator)) |
365 | 0 | { |
366 | 0 | #if VALIJSON_USE_EXCEPTIONS |
367 | 0 | try { |
368 | 0 | #endif |
369 | | // Clone individual enum values |
370 | 0 | for (const EnumValue *otherValue : other.m_enumValues) { |
371 | 0 | const EnumValue *value = otherValue->clone(); |
372 | 0 | #if VALIJSON_USE_EXCEPTIONS |
373 | 0 | try { |
374 | 0 | #endif |
375 | 0 | m_enumValues.push_back(value); |
376 | 0 | #if VALIJSON_USE_EXCEPTIONS |
377 | 0 | } catch (...) { |
378 | 0 | delete value; |
379 | 0 | value = nullptr; |
380 | 0 | throw; |
381 | 0 | } |
382 | 0 | } |
383 | 0 | } catch (...) { |
384 | | // Delete values already added to constraint |
385 | 0 | for (const EnumValue *value : m_enumValues) { |
386 | 0 | delete value; |
387 | 0 | } |
388 | 0 | throw; |
389 | 0 | #endif |
390 | 0 | } |
391 | 0 | } |
392 | | |
393 | | ~EnumConstraint() override |
394 | 0 | { |
395 | 0 | for (const EnumValue *value : m_enumValues) { |
396 | 0 | delete value; |
397 | 0 | } |
398 | 0 | } |
399 | | |
400 | | void addValue(const adapters::Adapter &value) |
401 | 0 | { |
402 | | // TODO: Freeze value using custom alloc/free functions |
403 | 0 | m_enumValues.push_back(value.freeze()); |
404 | 0 | } |
405 | | |
406 | | void addValue(const adapters::FrozenValue &value) |
407 | 0 | { |
408 | 0 | // TODO: Clone using custom alloc/free functions |
409 | 0 | m_enumValues.push_back(value.clone()); |
410 | 0 | } |
411 | | |
412 | | template<typename FunctorType> |
413 | | void applyToValues(const FunctorType &fn) const |
414 | | { |
415 | | for (const EnumValue *value : m_enumValues) { |
416 | | if (!fn(*value)) { |
417 | | return; |
418 | | } |
419 | | } |
420 | | } |
421 | | |
422 | | private: |
423 | | typedef adapters::FrozenValue EnumValue; |
424 | | |
425 | | typedef std::vector<const EnumValue *, internal::CustomAllocator<const EnumValue *>> EnumValues; |
426 | | |
427 | | EnumValues m_enumValues; |
428 | | }; |
429 | | |
430 | | /** |
431 | | * @brief Represent a 'format' constraint |
432 | | * |
433 | | * A format constraint restricts the content of string values, as defined by a set of commonly used formats. |
434 | | * |
435 | | * As this is an optional feature in JSON Schema, unrecognised formats will be treated as valid for any string value. |
436 | | */ |
437 | | class FormatConstraint: public BasicConstraint<FormatConstraint> |
438 | | { |
439 | | public: |
440 | | FormatConstraint() |
441 | 0 | : m_format() { } |
442 | | |
443 | | const std::string & getFormat() const |
444 | 0 | { |
445 | 0 | return m_format; |
446 | 0 | } |
447 | | |
448 | | void setFormat(const std::string & format) |
449 | 0 | { |
450 | 0 | m_format = format; |
451 | 0 | } |
452 | | |
453 | | private: |
454 | | std::string m_format; |
455 | | }; |
456 | | |
457 | | /** |
458 | | * @brief Represents non-singular 'items' and 'additionalItems' constraints |
459 | | * |
460 | | * Unlike the SingularItemsConstraint class, this class represents an 'items' |
461 | | * constraint that specifies an array of sub-schemas, which should be used to |
462 | | * validate each item in an array, in sequence. It also represents an optional |
463 | | * 'additionalItems' sub-schema that should be used when an array contains |
464 | | * more values than there are sub-schemas in the 'items' constraint. |
465 | | * |
466 | | * The prefix 'Linear' comes from the fact that this class contains a list of |
467 | | * sub-schemas that corresponding array items must be validated against, and |
468 | | * this validation is performed linearly (i.e. in sequence). |
469 | | */ |
470 | | class LinearItemsConstraint: public BasicConstraint<LinearItemsConstraint> |
471 | | { |
472 | | public: |
473 | | LinearItemsConstraint() |
474 | | : m_itemSubschemas(Allocator::rebind<const Subschema *>::other(m_allocator)), |
475 | 0 | m_additionalItemsSubschema(nullptr) { } |
476 | | |
477 | | LinearItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) |
478 | | : BasicConstraint(allocFn, freeFn), |
479 | | m_itemSubschemas(Allocator::rebind<const Subschema *>::other(m_allocator)), |
480 | 0 | m_additionalItemsSubschema(nullptr) { } |
481 | | |
482 | | void addItemSubschema(const Subschema *subschema) |
483 | 0 | { |
484 | 0 | m_itemSubschemas.push_back(subschema); |
485 | 0 | } |
486 | | |
487 | | template<typename FunctorType> |
488 | | void applyToItemSubschemas(const FunctorType &fn) const |
489 | | { |
490 | | unsigned int index = 0; |
491 | | for (const Subschema *subschema : m_itemSubschemas) { |
492 | | if (!fn(index, subschema)) { |
493 | | return; |
494 | | } |
495 | | |
496 | | index++; |
497 | | } |
498 | | } |
499 | | |
500 | | const Subschema * getAdditionalItemsSubschema() const |
501 | 0 | { |
502 | 0 | return m_additionalItemsSubschema; |
503 | 0 | } |
504 | | |
505 | | size_t getItemSubschemaCount() const |
506 | 0 | { |
507 | 0 | return m_itemSubschemas.size(); |
508 | 0 | } |
509 | | |
510 | | void setAdditionalItemsSubschema(const Subschema *subschema) |
511 | 0 | { |
512 | 0 | m_additionalItemsSubschema = subschema; |
513 | 0 | } |
514 | | |
515 | | private: |
516 | | typedef std::vector<const Subschema *, internal::CustomAllocator<const Subschema *>> Subschemas; |
517 | | |
518 | | Subschemas m_itemSubschemas; |
519 | | |
520 | | const Subschema* m_additionalItemsSubschema; |
521 | | }; |
522 | | |
523 | | /** |
524 | | * @brief Represents 'maximum' and 'exclusiveMaximum' constraints |
525 | | */ |
526 | | class MaximumConstraint: public BasicConstraint<MaximumConstraint> |
527 | | { |
528 | | public: |
529 | | MaximumConstraint() |
530 | | : m_maximum(std::numeric_limits<double>::infinity()), |
531 | 0 | m_exclusiveMaximum(false) { } |
532 | | |
533 | | MaximumConstraint(CustomAlloc allocFn, CustomFree freeFn) |
534 | | : BasicConstraint(allocFn, freeFn), |
535 | | m_maximum(std::numeric_limits<double>::infinity()), |
536 | 0 | m_exclusiveMaximum(false) { } |
537 | | |
538 | | bool getExclusiveMaximum() const |
539 | 0 | { |
540 | 0 | return m_exclusiveMaximum; |
541 | 0 | } |
542 | | |
543 | | void setExclusiveMaximum(bool newExclusiveMaximum) |
544 | 0 | { |
545 | 0 | m_exclusiveMaximum = newExclusiveMaximum; |
546 | 0 | } |
547 | | |
548 | | double getMaximum() const |
549 | 0 | { |
550 | 0 | return m_maximum; |
551 | 0 | } |
552 | | |
553 | | void setMaximum(double newMaximum) |
554 | 0 | { |
555 | 0 | m_maximum = newMaximum; |
556 | 0 | } |
557 | | |
558 | | private: |
559 | | double m_maximum; |
560 | | bool m_exclusiveMaximum; |
561 | | }; |
562 | | |
563 | | /** |
564 | | * @brief Represents a 'maxItems' constraint |
565 | | */ |
566 | | class MaxItemsConstraint: public BasicConstraint<MaxItemsConstraint> |
567 | | { |
568 | | public: |
569 | | MaxItemsConstraint() |
570 | 0 | : m_maxItems(std::numeric_limits<uint64_t>::max()) { } |
571 | | |
572 | | MaxItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) |
573 | | : BasicConstraint(allocFn, freeFn), |
574 | 0 | m_maxItems(std::numeric_limits<uint64_t>::max()) { } |
575 | | |
576 | | uint64_t getMaxItems() const |
577 | 0 | { |
578 | 0 | return m_maxItems; |
579 | 0 | } |
580 | | |
581 | | void setMaxItems(uint64_t newMaxItems) |
582 | 0 | { |
583 | 0 | m_maxItems = newMaxItems; |
584 | 0 | } |
585 | | |
586 | | private: |
587 | | uint64_t m_maxItems; |
588 | | }; |
589 | | |
590 | | /** |
591 | | * @brief Represents a 'maxLength' constraint |
592 | | */ |
593 | | class MaxLengthConstraint: public BasicConstraint<MaxLengthConstraint> |
594 | | { |
595 | | public: |
596 | | MaxLengthConstraint() |
597 | 0 | : m_maxLength(std::numeric_limits<uint64_t>::max()) { } |
598 | | |
599 | | MaxLengthConstraint(CustomAlloc allocFn, CustomFree freeFn) |
600 | | : BasicConstraint(allocFn, freeFn), |
601 | 0 | m_maxLength(std::numeric_limits<uint64_t>::max()) { } |
602 | | |
603 | | uint64_t getMaxLength() const |
604 | 0 | { |
605 | 0 | return m_maxLength; |
606 | 0 | } |
607 | | |
608 | | void setMaxLength(uint64_t newMaxLength) |
609 | 0 | { |
610 | 0 | m_maxLength = newMaxLength; |
611 | 0 | } |
612 | | |
613 | | private: |
614 | | uint64_t m_maxLength; |
615 | | }; |
616 | | |
617 | | /** |
618 | | * @brief Represents a 'maxProperties' constraint |
619 | | */ |
620 | | class MaxPropertiesConstraint: public BasicConstraint<MaxPropertiesConstraint> |
621 | | { |
622 | | public: |
623 | | MaxPropertiesConstraint() |
624 | 0 | : m_maxProperties(std::numeric_limits<uint64_t>::max()) { } |
625 | | |
626 | | MaxPropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn) |
627 | | : BasicConstraint(allocFn, freeFn), |
628 | 0 | m_maxProperties(std::numeric_limits<uint64_t>::max()) { } |
629 | | |
630 | | uint64_t getMaxProperties() const |
631 | 0 | { |
632 | 0 | return m_maxProperties; |
633 | 0 | } |
634 | | |
635 | | void setMaxProperties(uint64_t newMaxProperties) |
636 | 0 | { |
637 | 0 | m_maxProperties = newMaxProperties; |
638 | 0 | } |
639 | | |
640 | | private: |
641 | | uint64_t m_maxProperties; |
642 | | }; |
643 | | |
644 | | /** |
645 | | * @brief Represents 'minimum' and 'exclusiveMinimum' constraints |
646 | | */ |
647 | | class MinimumConstraint: public BasicConstraint<MinimumConstraint> |
648 | | { |
649 | | public: |
650 | | MinimumConstraint() |
651 | | : m_minimum(-std::numeric_limits<double>::infinity()), |
652 | 0 | m_exclusiveMinimum(false) { } |
653 | | |
654 | | MinimumConstraint(CustomAlloc allocFn, CustomFree freeFn) |
655 | | : BasicConstraint(allocFn, freeFn), |
656 | | m_minimum(-std::numeric_limits<double>::infinity()), |
657 | 0 | m_exclusiveMinimum(false) { } |
658 | | |
659 | | bool getExclusiveMinimum() const |
660 | 0 | { |
661 | 0 | return m_exclusiveMinimum; |
662 | 0 | } |
663 | | |
664 | | void setExclusiveMinimum(bool newExclusiveMinimum) |
665 | 0 | { |
666 | 0 | m_exclusiveMinimum = newExclusiveMinimum; |
667 | 0 | } |
668 | | |
669 | | double getMinimum() const |
670 | 0 | { |
671 | 0 | return m_minimum; |
672 | 0 | } |
673 | | |
674 | | void setMinimum(double newMinimum) |
675 | 0 | { |
676 | 0 | m_minimum = newMinimum; |
677 | 0 | } |
678 | | |
679 | | private: |
680 | | double m_minimum; |
681 | | bool m_exclusiveMinimum; |
682 | | }; |
683 | | |
684 | | /** |
685 | | * @brief Represents a 'minItems' constraint |
686 | | */ |
687 | | class MinItemsConstraint: public BasicConstraint<MinItemsConstraint> |
688 | | { |
689 | | public: |
690 | | MinItemsConstraint() |
691 | 0 | : m_minItems(0) { } |
692 | | |
693 | | MinItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) |
694 | | : BasicConstraint(allocFn, freeFn), |
695 | 0 | m_minItems(0) { } |
696 | | |
697 | | uint64_t getMinItems() const |
698 | 0 | { |
699 | 0 | return m_minItems; |
700 | 0 | } |
701 | | |
702 | | void setMinItems(uint64_t newMinItems) |
703 | 0 | { |
704 | 0 | m_minItems = newMinItems; |
705 | 0 | } |
706 | | |
707 | | private: |
708 | | uint64_t m_minItems; |
709 | | }; |
710 | | |
711 | | /** |
712 | | * @brief Represents a 'minLength' constraint |
713 | | */ |
714 | | class MinLengthConstraint: public BasicConstraint<MinLengthConstraint> |
715 | | { |
716 | | public: |
717 | | MinLengthConstraint() |
718 | 0 | : m_minLength(0) { } |
719 | | |
720 | | MinLengthConstraint(CustomAlloc allocFn, CustomFree freeFn) |
721 | | : BasicConstraint(allocFn, freeFn), |
722 | 0 | m_minLength(0) { } |
723 | | |
724 | | uint64_t getMinLength() const |
725 | 0 | { |
726 | 0 | return m_minLength; |
727 | 0 | } |
728 | | |
729 | | void setMinLength(uint64_t newMinLength) |
730 | 0 | { |
731 | 0 | m_minLength = newMinLength; |
732 | 0 | } |
733 | | |
734 | | private: |
735 | | uint64_t m_minLength; |
736 | | }; |
737 | | |
738 | | /** |
739 | | * @brief Represents a 'minProperties' constraint |
740 | | */ |
741 | | class MinPropertiesConstraint: public BasicConstraint<MinPropertiesConstraint> |
742 | | { |
743 | | public: |
744 | | MinPropertiesConstraint() |
745 | 0 | : m_minProperties(0) { } |
746 | | |
747 | | MinPropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn) |
748 | | : BasicConstraint(allocFn, freeFn), |
749 | 0 | m_minProperties(0) { } |
750 | | |
751 | | uint64_t getMinProperties() const |
752 | 0 | { |
753 | 0 | return m_minProperties; |
754 | 0 | } |
755 | | |
756 | | void setMinProperties(uint64_t newMinProperties) |
757 | 0 | { |
758 | 0 | m_minProperties = newMinProperties; |
759 | 0 | } |
760 | | |
761 | | private: |
762 | | uint64_t m_minProperties; |
763 | | }; |
764 | | |
765 | | /** |
766 | | * @brief Represents either 'multipleOf' or 'divisibleBy' constraints where |
767 | | * the divisor is a floating point number |
768 | | */ |
769 | | class MultipleOfDoubleConstraint: |
770 | | public BasicConstraint<MultipleOfDoubleConstraint> |
771 | | { |
772 | | public: |
773 | | MultipleOfDoubleConstraint() |
774 | 0 | : m_value(1.) { } |
775 | | |
776 | | MultipleOfDoubleConstraint(CustomAlloc allocFn, CustomFree freeFn) |
777 | | : BasicConstraint(allocFn, freeFn), |
778 | 0 | m_value(1.) { } |
779 | | |
780 | | double getDivisor() const |
781 | 0 | { |
782 | 0 | return m_value; |
783 | 0 | } |
784 | | |
785 | | void setDivisor(double newValue) |
786 | 0 | { |
787 | 0 | m_value = newValue; |
788 | 0 | } |
789 | | |
790 | | private: |
791 | | double m_value; |
792 | | }; |
793 | | |
794 | | /** |
795 | | * @brief Represents either 'multipleOf' or 'divisibleBy' constraints where |
796 | | * the divisor is of integer type |
797 | | */ |
798 | | class MultipleOfIntConstraint: |
799 | | public BasicConstraint<MultipleOfIntConstraint> |
800 | | { |
801 | | public: |
802 | | MultipleOfIntConstraint() |
803 | 0 | : m_value(1) { } |
804 | | |
805 | | MultipleOfIntConstraint(CustomAlloc allocFn, CustomFree freeFn) |
806 | | : BasicConstraint(allocFn, freeFn), |
807 | 0 | m_value(1) { } |
808 | | |
809 | | int64_t getDivisor() const |
810 | 0 | { |
811 | 0 | return m_value; |
812 | 0 | } |
813 | | |
814 | | void setDivisor(int64_t newValue) |
815 | 0 | { |
816 | 0 | m_value = newValue; |
817 | 0 | } |
818 | | |
819 | | private: |
820 | | int64_t m_value; |
821 | | }; |
822 | | |
823 | | /** |
824 | | * @brief Represents a 'not' constraint |
825 | | */ |
826 | | class NotConstraint: public BasicConstraint<NotConstraint> |
827 | | { |
828 | | public: |
829 | | NotConstraint() |
830 | 0 | : m_subschema(nullptr) { } |
831 | | |
832 | | NotConstraint(CustomAlloc allocFn, CustomFree freeFn) |
833 | | : BasicConstraint(allocFn, freeFn), |
834 | 0 | m_subschema(nullptr) { } |
835 | | |
836 | | const Subschema * getSubschema() const |
837 | 0 | { |
838 | 0 | return m_subschema; |
839 | 0 | } |
840 | | |
841 | | void setSubschema(const Subschema *subschema) |
842 | 0 | { |
843 | 0 | m_subschema = subschema; |
844 | 0 | } |
845 | | |
846 | | private: |
847 | | const Subschema *m_subschema; |
848 | | }; |
849 | | |
850 | | /** |
851 | | * @brief Represents a 'oneOf' constraint. |
852 | | */ |
853 | | class OneOfConstraint: public BasicConstraint<OneOfConstraint> |
854 | | { |
855 | | public: |
856 | | OneOfConstraint() |
857 | 0 | : m_subschemas(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
858 | | |
859 | | OneOfConstraint(CustomAlloc allocFn, CustomFree freeFn) |
860 | | : BasicConstraint(allocFn, freeFn), |
861 | 0 | m_subschemas(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
862 | | |
863 | | void addSubschema(const Subschema *subschema) |
864 | 0 | { |
865 | 0 | m_subschemas.push_back(subschema); |
866 | 0 | } |
867 | | |
868 | | template<typename FunctorType> |
869 | | void applyToSubschemas(const FunctorType &fn) const |
870 | | { |
871 | | unsigned int index = 0; |
872 | | for (const Subschema *subschema : m_subschemas) { |
873 | | if (!fn(index, subschema)) { |
874 | | return; |
875 | | } |
876 | | |
877 | | index++; |
878 | | } |
879 | | } |
880 | | |
881 | | private: |
882 | | typedef std::vector<const Subschema *, internal::CustomAllocator<const Subschema *>> Subschemas; |
883 | | |
884 | | /// Collection of sub-schemas, exactly one of which must be satisfied |
885 | | Subschemas m_subschemas; |
886 | | }; |
887 | | |
888 | | /** |
889 | | * @brief Represents a 'pattern' constraint |
890 | | */ |
891 | | class PatternConstraint: public BasicConstraint<PatternConstraint> |
892 | | { |
893 | | public: |
894 | | PatternConstraint() |
895 | 0 | : m_pattern(Allocator::rebind<char>::other(m_allocator)) { } |
896 | | |
897 | | PatternConstraint(CustomAlloc allocFn, CustomFree freeFn) |
898 | | : BasicConstraint(allocFn, freeFn), |
899 | 0 | m_pattern(Allocator::rebind<char>::other(m_allocator)) { } |
900 | | |
901 | | template<typename AllocatorType> |
902 | | bool getPattern(std::basic_string<char, std::char_traits<char>, AllocatorType> &result) const |
903 | | { |
904 | | result.assign(m_pattern.c_str()); |
905 | | return true; |
906 | | } |
907 | | |
908 | | template<typename AllocatorType> |
909 | | std::basic_string<char, std::char_traits<char>, AllocatorType> getPattern( |
910 | | const AllocatorType &alloc = AllocatorType()) const |
911 | | { |
912 | | return std::basic_string<char, std::char_traits<char>, AllocatorType>(m_pattern.c_str(), alloc); |
913 | | } |
914 | | |
915 | | template<typename AllocatorType> |
916 | | void setPattern(const std::basic_string<char, std::char_traits<char>, AllocatorType> &pattern) |
917 | 0 | { |
918 | 0 | m_pattern.assign(pattern.c_str()); |
919 | 0 | } |
920 | | |
921 | | private: |
922 | | String m_pattern; |
923 | | }; |
924 | | |
925 | | class PolyConstraint : public Constraint |
926 | | { |
927 | | public: |
928 | | bool accept(ConstraintVisitor &visitor) const override |
929 | 0 | { |
930 | 0 | return visitor.visit(*static_cast<const PolyConstraint*>(this)); |
931 | 0 | } |
932 | | |
933 | | OwningPointer clone(CustomAlloc allocFn, CustomFree freeFn) const override |
934 | 0 | { |
935 | 0 | // smart pointer to automatically free raw memory on exception |
936 | 0 | typedef std::unique_ptr<Constraint, CustomFree> RawOwningPointer; |
937 | 0 | auto ptr = RawOwningPointer(static_cast<Constraint*>(allocFn(sizeOf())), freeFn); |
938 | 0 | if (!ptr) { |
939 | 0 | throwRuntimeError("Failed to allocate memory for cloned constraint"); |
940 | 0 | } |
941 | 0 |
|
942 | 0 | // constructor might throw but the memory will be taken care of anyways |
943 | 0 | (void)cloneInto(ptr.get()); |
944 | 0 |
|
945 | 0 | // implicitly convert to smart pointer that will also destroy object instance |
946 | 0 | return ptr; |
947 | 0 | } |
948 | | |
949 | | virtual bool validate(const adapters::Adapter &target, |
950 | | const std::vector<std::string>& context, |
951 | | valijson::ValidationResults *results) const = 0; |
952 | | |
953 | | private: |
954 | | virtual Constraint * cloneInto(void *) const = 0; |
955 | | |
956 | | virtual size_t sizeOf() const = 0; |
957 | | }; |
958 | | |
959 | | /** |
960 | | * @brief Represents a combination of 'properties', 'patternProperties' and |
961 | | * 'additionalProperties' constraints |
962 | | */ |
963 | | class PropertiesConstraint: public BasicConstraint<PropertiesConstraint> |
964 | | { |
965 | | public: |
966 | | PropertiesConstraint() |
967 | | : m_properties(std::less<String>(), m_allocator), |
968 | | m_patternProperties(std::less<String>(), m_allocator), |
969 | 0 | m_additionalProperties(nullptr) { } |
970 | | |
971 | | PropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn) |
972 | | : BasicConstraint(allocFn, freeFn), |
973 | | m_properties(std::less<String>(), m_allocator), |
974 | | m_patternProperties(std::less<String>(), m_allocator), |
975 | 0 | m_additionalProperties(nullptr) { } |
976 | | |
977 | | bool addPatternPropertySubschema(const char *patternProperty, const Subschema *subschema) |
978 | 0 | { |
979 | 0 | return m_patternProperties.insert(PropertySchemaMap::value_type( |
980 | 0 | String(patternProperty, m_allocator), subschema)).second; |
981 | 0 | } |
982 | | |
983 | | template<typename AllocatorType> |
984 | | bool addPatternPropertySubschema(const std::basic_string<char, |
985 | | std::char_traits<char>, AllocatorType> &patternProperty, |
986 | | const Subschema *subschema) |
987 | 0 | { |
988 | 0 | return addPatternPropertySubschema(patternProperty.c_str(), subschema); |
989 | 0 | } |
990 | | |
991 | | bool addPropertySubschema(const char *propertyName, |
992 | | const Subschema *subschema) |
993 | 0 | { |
994 | 0 | return m_properties.insert(PropertySchemaMap::value_type( |
995 | 0 | String(propertyName, m_allocator), subschema)).second; |
996 | 0 | } |
997 | | |
998 | | template<typename AllocatorType> |
999 | | bool addPropertySubschema(const std::basic_string<char, |
1000 | | std::char_traits<char>, AllocatorType> &propertyName, |
1001 | | const Subschema *subschema) |
1002 | 0 | { |
1003 | 0 | return addPropertySubschema(propertyName.c_str(), subschema); |
1004 | 0 | } |
1005 | | |
1006 | | template<typename FunctorType> |
1007 | | void applyToPatternProperties(const FunctorType &fn) const |
1008 | | { |
1009 | | typedef typename PropertySchemaMap::value_type ValueType; |
1010 | | for (const ValueType &value : m_patternProperties) { |
1011 | | if (!fn(value.first, value.second)) { |
1012 | | return; |
1013 | | } |
1014 | | } |
1015 | | } |
1016 | | |
1017 | | template<typename FunctorType> |
1018 | | void applyToProperties(const FunctorType &fn) const |
1019 | | { |
1020 | | typedef typename PropertySchemaMap::value_type ValueType; |
1021 | | for (const ValueType &value : m_properties) { |
1022 | | if (!fn(value.first, value.second)) { |
1023 | | return; |
1024 | | } |
1025 | | } |
1026 | | } |
1027 | | |
1028 | | const Subschema * getAdditionalPropertiesSubschema() const |
1029 | 0 | { |
1030 | 0 | return m_additionalProperties; |
1031 | 0 | } |
1032 | | |
1033 | | void setAdditionalPropertiesSubschema(const Subschema *subschema) |
1034 | 0 | { |
1035 | 0 | m_additionalProperties = subschema; |
1036 | 0 | } |
1037 | | |
1038 | | private: |
1039 | | typedef std::map< |
1040 | | String, |
1041 | | const Subschema *, |
1042 | | std::less<String>, |
1043 | | internal::CustomAllocator<std::pair<const String, const Subschema *>> |
1044 | | > PropertySchemaMap; |
1045 | | |
1046 | | PropertySchemaMap m_properties; |
1047 | | PropertySchemaMap m_patternProperties; |
1048 | | |
1049 | | const Subschema *m_additionalProperties; |
1050 | | }; |
1051 | | |
1052 | | class PropertyNamesConstraint: public BasicConstraint<PropertyNamesConstraint> |
1053 | | { |
1054 | | public: |
1055 | | PropertyNamesConstraint() |
1056 | 0 | : m_subschema(nullptr) { } |
1057 | | |
1058 | | PropertyNamesConstraint(CustomAlloc allocFn, CustomFree freeFn) |
1059 | | : BasicConstraint(allocFn, freeFn), |
1060 | 0 | m_subschema(nullptr) { } |
1061 | | |
1062 | | const Subschema * getSubschema() const |
1063 | 0 | { |
1064 | 0 | return m_subschema; |
1065 | 0 | } |
1066 | | |
1067 | | void setSubschema(const Subschema *subschema) |
1068 | 0 | { |
1069 | 0 | m_subschema = subschema; |
1070 | 0 | } |
1071 | | |
1072 | | private: |
1073 | | const Subschema *m_subschema; |
1074 | | }; |
1075 | | |
1076 | | /** |
1077 | | * @brief Represents a 'required' constraint |
1078 | | */ |
1079 | | class RequiredConstraint: public BasicConstraint<RequiredConstraint> |
1080 | | { |
1081 | | public: |
1082 | | RequiredConstraint() |
1083 | 0 | : m_requiredProperties(std::less<String>(), m_allocator) { } |
1084 | | |
1085 | | RequiredConstraint(CustomAlloc allocFn, CustomFree freeFn) |
1086 | | : BasicConstraint(allocFn, freeFn), |
1087 | 0 | m_requiredProperties(std::less<String>(), m_allocator) { } |
1088 | | |
1089 | | bool addRequiredProperty(const char *propertyName) |
1090 | 0 | { |
1091 | 0 | return m_requiredProperties.insert(String(propertyName, |
1092 | 0 | Allocator::rebind<char>::other(m_allocator))).second; |
1093 | 0 | } |
1094 | | |
1095 | | template<typename AllocatorType> |
1096 | | bool addRequiredProperty(const std::basic_string<char, std::char_traits<char>, AllocatorType> &propertyName) |
1097 | 0 | { |
1098 | 0 | return addRequiredProperty(propertyName.c_str()); |
1099 | 0 | } |
1100 | | |
1101 | | template<typename FunctorType> |
1102 | | void applyToRequiredProperties(const FunctorType &fn) const |
1103 | | { |
1104 | | for (const String &propertyName : m_requiredProperties) { |
1105 | | if (!fn(propertyName)) { |
1106 | | return; |
1107 | | } |
1108 | | } |
1109 | | } |
1110 | | |
1111 | | private: |
1112 | | typedef std::set<String, std::less<String>, |
1113 | | internal::CustomAllocator<String>> RequiredProperties; |
1114 | | |
1115 | | RequiredProperties m_requiredProperties; |
1116 | | }; |
1117 | | |
1118 | | /** |
1119 | | * @brief Represents an 'items' constraint that specifies one sub-schema |
1120 | | * |
1121 | | * A value is considered valid against this constraint if it is an array, and |
1122 | | * each item in the array validates against the sub-schema specified by this |
1123 | | * constraint. |
1124 | | * |
1125 | | * The prefix 'Singular' comes from the fact that array items must validate |
1126 | | * against exactly one sub-schema. |
1127 | | */ |
1128 | | class SingularItemsConstraint: public BasicConstraint<SingularItemsConstraint> |
1129 | | { |
1130 | | public: |
1131 | | SingularItemsConstraint() |
1132 | 0 | : m_itemsSubschema(nullptr) { } |
1133 | | |
1134 | | SingularItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) |
1135 | | : BasicConstraint(allocFn, freeFn), |
1136 | 0 | m_itemsSubschema(nullptr) { } |
1137 | | |
1138 | | const Subschema * getItemsSubschema() const |
1139 | 0 | { |
1140 | 0 | return m_itemsSubschema; |
1141 | 0 | } |
1142 | | |
1143 | | void setItemsSubschema(const Subschema *subschema) |
1144 | 0 | { |
1145 | 0 | m_itemsSubschema = subschema; |
1146 | 0 | } |
1147 | | |
1148 | | private: |
1149 | | const Subschema *m_itemsSubschema; |
1150 | | }; |
1151 | | |
1152 | | /** |
1153 | | * @brief Represents a 'type' constraint. |
1154 | | */ |
1155 | | class TypeConstraint: public BasicConstraint<TypeConstraint> |
1156 | | { |
1157 | | public: |
1158 | | enum JsonType { |
1159 | | kAny, |
1160 | | kArray, |
1161 | | kBoolean, |
1162 | | kInteger, |
1163 | | kNull, |
1164 | | kNumber, |
1165 | | kObject, |
1166 | | kString |
1167 | | }; |
1168 | | |
1169 | | TypeConstraint() |
1170 | | : m_namedTypes(std::less<JsonType>(), m_allocator), |
1171 | 0 | m_schemaTypes(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
1172 | | |
1173 | | TypeConstraint(CustomAlloc allocFn, CustomFree freeFn) |
1174 | | : BasicConstraint(allocFn, freeFn), |
1175 | | m_namedTypes(std::less<JsonType>(), m_allocator), |
1176 | 0 | m_schemaTypes(Allocator::rebind<const Subschema *>::other(m_allocator)) { } |
1177 | | |
1178 | | void addNamedType(JsonType type) |
1179 | 0 | { |
1180 | 0 | m_namedTypes.insert(type); |
1181 | 0 | } |
1182 | | |
1183 | | void addSchemaType(const Subschema *subschema) |
1184 | 0 | { |
1185 | 0 | m_schemaTypes.push_back(subschema); |
1186 | 0 | } |
1187 | | |
1188 | | template<typename FunctorType> |
1189 | | void applyToNamedTypes(const FunctorType &fn) const |
1190 | | { |
1191 | | for (const JsonType namedType : m_namedTypes) { |
1192 | | if (!fn(namedType)) { |
1193 | | return; |
1194 | | } |
1195 | | } |
1196 | | } |
1197 | | |
1198 | | template<typename FunctorType> |
1199 | | void applyToSchemaTypes(const FunctorType &fn) const |
1200 | | { |
1201 | | unsigned int index = 0; |
1202 | | for (const Subschema *subschema : m_schemaTypes) { |
1203 | | if (!fn(index, subschema)) { |
1204 | | return; |
1205 | | } |
1206 | | |
1207 | | index++; |
1208 | | } |
1209 | | } |
1210 | | |
1211 | | template<typename AllocatorType> |
1212 | | static JsonType jsonTypeFromString(const std::basic_string<char, |
1213 | | std::char_traits<char>, AllocatorType> &typeName) |
1214 | 0 | { |
1215 | 0 | if (typeName.compare("any") == 0) { |
1216 | 0 | return kAny; |
1217 | 0 | } else if (typeName.compare("array") == 0) { |
1218 | 0 | return kArray; |
1219 | 0 | } else if (typeName.compare("boolean") == 0) { |
1220 | 0 | return kBoolean; |
1221 | 0 | } else if (typeName.compare("integer") == 0) { |
1222 | 0 | return kInteger; |
1223 | 0 | } else if (typeName.compare("null") == 0) { |
1224 | 0 | return kNull; |
1225 | 0 | } else if (typeName.compare("number") == 0) { |
1226 | 0 | return kNumber; |
1227 | 0 | } else if (typeName.compare("object") == 0) { |
1228 | 0 | return kObject; |
1229 | 0 | } else if (typeName.compare("string") == 0) { |
1230 | 0 | return kString; |
1231 | 0 | } |
1232 | | |
1233 | 0 | throwRuntimeError("Unrecognised JSON type name '" + |
1234 | 0 | std::string(typeName.c_str()) + "'"); |
1235 | 0 | abort(); |
1236 | 0 | } |
1237 | | |
1238 | | private: |
1239 | | typedef std::set<JsonType, std::less<JsonType>, internal::CustomAllocator<JsonType>> NamedTypes; |
1240 | | |
1241 | | typedef std::vector<const Subschema *, |
1242 | | Allocator::rebind<const Subschema *>::other> SchemaTypes; |
1243 | | |
1244 | | /// Set of named JSON types that serve as valid types |
1245 | | NamedTypes m_namedTypes; |
1246 | | |
1247 | | /// Set of sub-schemas that serve as valid types |
1248 | | SchemaTypes m_schemaTypes; |
1249 | | }; |
1250 | | |
1251 | | /** |
1252 | | * @brief Represents a 'uniqueItems' constraint |
1253 | | */ |
1254 | | class UniqueItemsConstraint: public BasicConstraint<UniqueItemsConstraint> |
1255 | | { |
1256 | | public: |
1257 | 0 | UniqueItemsConstraint() = default; |
1258 | | |
1259 | | UniqueItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) |
1260 | 0 | : BasicConstraint(allocFn, freeFn) { } |
1261 | | }; |
1262 | | |
1263 | | } // namespace constraints |
1264 | | } // namespace valijson |
1265 | | |
1266 | | #ifdef _MSC_VER |
1267 | | #pragma warning( pop ) |
1268 | | #endif |