Split ItemsConstraint into SingularItemsConstraint and LinearItemsConstraint, using CustomAllocator where necessary

This commit is contained in:
Tristan Penman 2015-12-28 13:14:41 +11:00
parent a02048cfcf
commit 579b0708ee
4 changed files with 411 additions and 233 deletions

View File

@ -248,67 +248,70 @@ struct EnumConstraint: BasicConstraint<EnumConstraint>
};
/**
* @brief Represents a pair of 'items' and 'additionalItems' constraints.
* @brief Represents non-singular 'items' and 'additionalItems' constraints
*
* Unlike the SingularItemsConstraint class, this class represents an 'items'
* constraint that specifies an array of sub-schemas, which should be used to
* validate each item in an array, in sequence. It also represents an optional
* 'additionalItems' sub-schema that should be used when an array contains
* more values than there are sub-schemas in the 'items' constraint.
*
* The prefix 'Linear' comes from the fact that this class contains a list of
* sub-schemas that corresponding array items must be validated against, and
* this validation is performed linearly (i.e. in sequence).
*/
struct ItemsConstraint: BasicConstraint<ItemsConstraint>
class LinearItemsConstraint: public BasicConstraint<LinearItemsConstraint>
{
typedef std::vector<const Subschema *> Schemas;
public:
LinearItemsConstraint()
: itemSubschemas(Allocator::rebind<const Subschema *>::other(allocator)),
additionalItemsSubschema(NULL) { }
/**
* @brief Construct a singular item constraint that allows no additional
* items
*
* @param itemSchema
*/
ItemsConstraint(const Subschema *itemSchema)
: itemSchema(itemSchema),
additionalItemsSchema(NULL) { }
LinearItemsConstraint(CustomAlloc allocFn, CustomFree freeFn)
: BasicConstraint(allocFn, freeFn),
itemSubschemas(Allocator::rebind<const Subschema *>::other(allocator)),
additionalItemsSubschema(NULL) { }
/**
* @brief Construct a singular item schema that allows additional items
*
* @param itemSchema
* @param additionalItemsSchema
*/
ItemsConstraint(const Subschema *itemSchema,
const Subschema *additionalItemsSchema)
: itemSchema(itemSchema),
additionalItemsSchema(additionalItemsSchema) { }
void addItemSubschema(const Subschema *subschema)
{
itemSubschemas.push_back(subschema);
}
/**
* @brief Construct a plural items constraint that does not allow for
* additional item schemas
*
* @param itemSchemas collection of item schemas
*/
ItemsConstraint(const Schemas &itemSchemas)
: itemSchema(NULL),
itemSchemas(itemSchemas),
additionalItemsSchema(NULL) { }
template<typename FunctorType>
void applyToItemSubschemas(const FunctorType &fn) const
{
unsigned int index = 0;
BOOST_FOREACH( const Subschema *subschema, itemSubschemas ) {
if (!fn(index, subschema)) {
return;
}
/**
* @brief Construct a plural items constraint that allows additional items
*
* @param itemSchemas
* @param additionalItemsSchema
*/
ItemsConstraint(const Schemas &itemSchemas,
const Subschema *additionalItemsSchema)
: itemSchema(NULL),
itemSchemas(itemSchemas),
additionalItemsSchema(additionalItemsSchema) { }
index++;
}
}
/**
* @brief Copy constructor
*/
ItemsConstraint(const ItemsConstraint &other)
: itemSchema(other.itemSchema),
itemSchemas(other.itemSchemas),
additionalItemsSchema(other.additionalItemsSchema) { }
const Subschema * getAdditionalItemsSubschema() const
{
return additionalItemsSubschema;
}
const Subschema* itemSchema;
const Schemas itemSchemas;
const Subschema* additionalItemsSchema;
size_t getItemSubschemaCount() const
{
return itemSubschemas.size();
}
void setAdditionalItemsSubschema(const Subschema *subschema)
{
additionalItemsSubschema = subschema;
}
private:
typedef std::vector<const Subschema *,
internal::CustomAllocator<const Subschema *> > Subschemas;
Subschemas itemSubschemas;
const Subschema* additionalItemsSubschema;
};
/**
@ -533,6 +536,36 @@ struct RequiredConstraint: BasicConstraint<RequiredConstraint>
const RequiredProperties requiredProperties;
};
/**
* @brief Represents an 'items' constraint that specifies one sub-schema
*
* A value is considered valid against this constraint if it is an array, and
* each item in the array validates against the sub-schema specified by this
* constraint.
*
* The prefix 'Singular' comes from the fact that array items must validate
* against exactly one sub-schema.
*/
class SingularItemsConstraint: public BasicConstraint<SingularItemsConstraint>
{
public:
SingularItemsConstraint()
: itemsSubschema(NULL) { }
const Subschema * getItemsSubschema() const
{
return itemsSubschema;
}
void setItemsSubschema(const Subschema *subschema)
{
itemsSubschema = subschema;
}
private:
const Subschema *itemsSubschema;
};
/**
* @brief Represents a 'type' constraint.
*/

View File

@ -6,7 +6,6 @@ namespace valijson {
namespace constraints {
struct EnumConstraint;
struct ItemsConstraint;
struct FormatConstraint;
struct MaximumConstraint;
struct MaxItemsConstraint;
@ -27,7 +26,9 @@ struct UniqueItemsConstraint;
class AllOfConstraint;
class AnyOfConstraint;
class DependenciesConstraint;
class LinearItemsConstraint;
class OneOfConstraint;
class SingularItemsConstraint;
/// Interface to allow usage of the visitor pattern with Constraints
class ConstraintVisitor
@ -39,7 +40,7 @@ protected:
typedef constraints::AnyOfConstraint AnyOfConstraint;
typedef constraints::DependenciesConstraint DependenciesConstraint;
typedef constraints::EnumConstraint EnumConstraint;
typedef constraints::ItemsConstraint ItemsConstraint;
typedef constraints::LinearItemsConstraint LinearItemsConstraint;
typedef constraints::MaximumConstraint MaximumConstraint;
typedef constraints::MaxItemsConstraint MaxItemsConstraint;
typedef constraints::MaxLengthConstraint MaxLengthConstraint;
@ -54,6 +55,7 @@ protected:
typedef constraints::PatternConstraint PatternConstraint;
typedef constraints::PropertiesConstraint PropertiesConstraint;
typedef constraints::RequiredConstraint RequiredConstraint;
typedef constraints::SingularItemsConstraint SingularItemsConstraint;
typedef constraints::TypeConstraint TypeConstraint;
typedef constraints::UniqueItemsConstraint UniqueItemsConstraint;
@ -63,7 +65,7 @@ public:
virtual bool visit(const AnyOfConstraint &) = 0;
virtual bool visit(const DependenciesConstraint &) = 0;
virtual bool visit(const EnumConstraint &) = 0;
virtual bool visit(const ItemsConstraint &) = 0;
virtual bool visit(const LinearItemsConstraint &) = 0;
virtual bool visit(const MaximumConstraint &) = 0;
virtual bool visit(const MaxItemsConstraint &) = 0;
virtual bool visit(const MaxLengthConstraint &) = 0;
@ -78,6 +80,7 @@ public:
virtual bool visit(const PatternConstraint &) = 0;
virtual bool visit(const PropertiesConstraint &) = 0;
virtual bool visit(const RequiredConstraint &) = 0;
virtual bool visit(const SingularItemsConstraint &) = 0;
virtual bool visit(const TypeConstraint &) = 0;
virtual bool visit(const UniqueItemsConstraint &) = 0;

View File

@ -199,22 +199,30 @@ private:
}
{
// Check for schema keywords that require the creation of a
// ItemsConstraint instance.
const typename AdapterType::Object::const_iterator
itemsItr = object.find("items"),
additionalitemsItr = object.find("additionalItems");
if (object.end() != itemsItr ||
object.end() != additionalitemsItr) {
rootSchema.addConstraintToSubschema(
makeItemsConstraint(rootSchema, rootNode,
itemsItr != object.end() ?
&itemsItr->second : NULL,
additionalitemsItr != object.end() ?
&additionalitemsItr->second : NULL,
currentScope, nodePath + "/items",
nodePath + "/additionalItems", fetchDoc),
&subschema);
const typename AdapterType::Object::const_iterator itemsItr =
object.find("items");
if (object.end() != itemsItr) {
if (!itemsItr->second.isArray()) {
rootSchema.addConstraintToSubschema(
makeSingularItemsConstraint(rootSchema, rootNode,
itemsItr->second, currentScope,
nodePath + "/items", fetchDoc),
&subschema);
} else {
const typename AdapterType::Object::const_iterator
additionalItemsItr = object.find("additionalItems");
rootSchema.addConstraintToSubschema(
makeLinearItemsConstraint(rootSchema, rootNode,
itemsItr != object.end() ?
&itemsItr->second : NULL,
additionalItemsItr != object.end() ?
&additionalItemsItr->second : NULL,
currentScope, nodePath + "/items",
nodePath + "/additionalItems", fetchDoc),
&subschema);
}
}
}
@ -728,7 +736,7 @@ private:
* @return pointer to a new ItemsConstraint that belongs to the caller
*/
template<typename AdapterType>
constraints::ItemsConstraint makeItemsConstraint(
constraints::LinearItemsConstraint makeLinearItemsConstraint(
Schema &rootSchema,
const AdapterType &rootNode,
const AdapterType *items,
@ -739,24 +747,27 @@ private:
const boost::optional<
typename FetchDocumentFunction<AdapterType>::Type > fetchDoc)
{
constraints::LinearItemsConstraint constraint;
// Construct a Schema object for the the additionalItems constraint,
// if the additionalItems property is present
const Subschema *additionalItemsSchema = NULL;
if (additionalItems) {
if (additionalItems->maybeBool()) {
// If the value of the additionalItems property is a boolean
// and is set to true, then additional array items do not need
// to satisfy any constraints.
if (additionalItems->asBool()) {
additionalItemsSchema = rootSchema.createSubschema();
constraint.setAdditionalItemsSubschema(
rootSchema.emptySubschema());
}
} else if (additionalItems->maybeObject()) {
// If the value of the additionalItems property is an object,
// then it should be parsed into a Schema object, which will be
// used to validate additional array items.
additionalItemsSchema = rootSchema.createSubschema();
const Subschema *subschema = rootSchema.createSubschema();
constraint.setAdditionalItemsSubschema(subschema);
populateSchema<AdapterType>(rootSchema, rootNode,
*additionalItems, *additionalItemsSchema, currentScope,
*additionalItems, *subschema, currentScope,
additionalItemsPath, fetchDoc);
} else {
// Any other format for the additionalItems property will result
@ -768,14 +779,12 @@ private:
// The default value for the additionalItems property is an empty
// object, which means that additional array items do not need to
// satisfy any constraints.
additionalItemsSchema = rootSchema.createSubschema();
constraint.setAdditionalItemsSubschema(rootSchema.emptySubschema());
}
// Construct a Schema object for each item in the items array, if an
// array is provided, or a single Schema object, in an object value is
// provided. If the items constraint is not provided, then array items
// Construct a Schema object for each item in the items array.
// If the items constraint is not provided, then array items
// will be validated against the additionalItems schema.
constraints::ItemsConstraint::Schemas itemSchemas;
if (items) {
if (items->isArray()) {
// If the items constraint contains an array, then it should
@ -786,61 +795,87 @@ private:
BOOST_FOREACH( const AdapterType v, items->getArray() ) {
const std::string childPath = itemsPath + "/" +
boost::lexical_cast<std::string>(index);
itemSchemas.push_back(rootSchema.createSubschema());
const Subschema &childSubschema = *itemSchemas.back();
const Subschema *subschema = rootSchema.createSubschema();
constraint.addItemSubschema(subschema);
populateSchema<AdapterType>(rootSchema, rootNode, v,
childSubschema, currentScope, childPath, fetchDoc);
*subschema, currentScope, childPath, fetchDoc);
index++;
}
// Create an ItemsConstraint object using the appropriate
// overloaded constructor.
if (additionalItemsSchema) {
return constraints::ItemsConstraint(itemSchemas,
additionalItemsSchema);
} else {
return constraints::ItemsConstraint(itemSchemas);
}
} else if (items->isObject()) {
// If the items constraint contains an object value, then it
// should contain a Schema that will be used to validate all
// items in a target array. Any schema defined by the
// additionalItems constraint will be ignored.
const Subschema *childSubschema = rootSchema.createSubschema();
populateSchema<AdapterType>(rootSchema, rootNode, *items,
*childSubschema, currentScope, itemsPath, fetchDoc);
if (additionalItemsSchema) {
return constraints::ItemsConstraint(childSubschema,
additionalItemsSchema);
} else {
return constraints::ItemsConstraint(childSubschema);
}
} else if (items->maybeObject()) {
// If a loosely-typed Adapter type is being used, then we'll
// assume that an empty schema has been provided.
const Subschema *childSubschema = rootSchema.createSubschema();
if (additionalItemsSchema) {
return constraints::ItemsConstraint(childSubschema,
additionalItemsSchema);
} else {
return constraints::ItemsConstraint(childSubschema);
}
} else {
// All other formats will result in an exception being thrown.
throw std::runtime_error(
"Expected array or object value for 'items'.");
"Expected array value for non-singular 'items' "
"constraint.");
}
}
if (additionalItemsSchema) {
return constraints::ItemsConstraint(rootSchema.emptySubschema(),
additionalItemsSchema);
return constraint;
}
/**
* @brief Make a new ItemsConstraint object.
*
* @param rootSchema The Schema instance, and root subschema,
* through which other subschemas can be
* created and modified
* @param rootNode Reference to the node from which JSON
* References will be resolved when they refer
* to the current document; used for recursive
* parsing of schemas
* @param items Optional pointer to a JSON node containing
* an object mapping property names to
* schemas.
* @param additionalItems Optional pointer to a JSON node containing
* an additional properties schema or a
* boolean value.
* @param currentScope URI for current resolution scope
* @param itemsPath JSON Pointer representing the path to
* the 'items' node
* @param additionalItemsPath JSON Pointer representing the path to
* the 'additionalItems' node
* @param fetchDoc Function to fetch remote JSON documents
* (optional)
*
* @return pointer to a new ItemsConstraint that belongs to the caller
*/
template<typename AdapterType>
constraints::SingularItemsConstraint makeSingularItemsConstraint(
Schema &rootSchema,
const AdapterType &rootNode,
const AdapterType &items,
const boost::optional<std::string> currentScope,
const std::string &itemsPath,
const boost::optional<
typename FetchDocumentFunction<AdapterType>::Type > fetchDoc)
{
constraints::SingularItemsConstraint constraint;
// Construct a Schema object for each item in the items array, if an
// array is provided, or a single Schema object, in an object value is
// provided. If the items constraint is not provided, then array items
// will be validated against the additionalItems schema.
if (items.isObject()) {
// If the items constraint contains an object value, then it
// should contain a Schema that will be used to validate all
// items in a target array. Any schema defined by the
// additionalItems constraint will be ignored.
const Subschema *subschema = rootSchema.createSubschema();
constraint.setItemsSubschema(subschema);
populateSchema<AdapterType>(rootSchema, rootNode, items,
*subschema, currentScope, itemsPath, fetchDoc);
} else if (items.maybeObject()) {
// If a loosely-typed Adapter type is being used, then we'll
// assume that an empty schema has been provided.
constraint.setItemsSubschema(rootSchema.emptySubschema());
} else {
// All other formats will result in an exception being thrown.
throw std::runtime_error(
"Expected object value for singular 'items' "
"constraint.");
}
return constraints::ItemsConstraint(rootSchema.emptySubschema());
return constraint;
}
/**

View File

@ -232,68 +232,52 @@ public:
}
/**
* @brief Validate against the items and additionalItems constraints
* represented by an ItemsConstraint object.
* @brief Validate a value against a LinearItemsConstraint
* A LinearItemsConstraint represents an 'items' constraint that specifies,
* for each item in array, an individual sub-schema that the item must
* validate against. The LinearItemsConstraint class also captures the
* presence of an 'additionalItems' constraint, which specifies a default
* sub-schema that should be used if an array contains more items than
* there are sub-schemas in the 'items' constraint.
*
* An items constraint restricts the values in array to those that match a
* given set of schemas. An item constraint can specify either an ordered
* list of child schemas that will be used to validate the corresponding
* value in the target array, or a single schema that will be used to
* validate all items.
* If the current value is not an array, validation always succeeds.
*
* If a list of child schemas is used, then the additionalItems constraint
* will also be considered. If present, the schema derived from the
* additionalItems constraint will be used to validate items that do not
* have a corresponding child schema in the items constraint. If the
* items constraint was not provided, then the additionalItems schema will
* be used to validate all items in the array.
* @param constraint SingularItemsConstraint to validate against
*
* @param constraint Constraint that the target must validate against.
*
* @return true if validatation succeeds, false otherwise.
* @returns \c true if validation is successful; \c false otherwise
*/
virtual bool visit(const ItemsConstraint &constraint)
virtual bool visit(const LinearItemsConstraint &constraint)
{
// Ignore values that are not arrays
if ((strictTypes && !target.isArray()) || (!target.maybeArray())) {
return true;
}
// Sub-schema to validate against when number of items in array exceeds
// the number of sub-schemas provided by the 'items' constraint
const Subschema * const additionalItemsSubschema =
constraint.getAdditionalItemsSubschema();
// Track how many items are validated using 'items' constraint
unsigned int numValidated = 0;
// Array to validate
const typename AdapterType::Array arr = target.asArray();
const size_t arrSize = arr.size();
// Track validation status
bool validated = true;
if (constraint.itemSchema) {
// Get access to the target as an object
const typename AdapterType::Array arr = target.asArray();
// Validate all items against single schema
unsigned int index = 0;
BOOST_FOREACH( const AdapterType arrayItem, arr ) {
std::vector<std::string> newContext = context;
newContext.push_back("[" + boost::lexical_cast<std::string>(index) + "]");
ValidationVisitor<AdapterType> v(arrayItem,
newContext, strictTypes, results);
if (!v.validateSchema(*constraint.itemSchema)) {
// Validate as many items as possible using 'items' sub-schemas
const size_t itemSubschemaCount = constraint.getItemSubschemaCount();
if (itemSubschemaCount > 0) {
if (!additionalItemsSubschema) {
if (arrSize > itemSubschemaCount) {
if (results) {
results->pushError(context, "Failed to validate item #" + boost::lexical_cast<std::string>(index) + " in array.");
validated = false;
} else {
return false;
}
}
++index;
}
} else if (!constraint.itemSchemas.empty()) {
// Get access to the target as an object
const typename AdapterType::Array arr = target.asArray();
if (!constraint.additionalItemsSchema) {
// Check that the array length is <= length of the itemsSchema list
if (arr.size() > constraint.itemSchemas.size()) {
if (results) {
results->pushError(context, "Array contains more items than allowed by items constraint.");
results->pushError(context,
"Array contains more items than allowed by "
"items constraint.");
validated = false;
} else {
return false;
@ -301,67 +285,59 @@ public:
}
}
// Validate items against the schema with the same index, or
// additionalItems schema
unsigned int index = 0;
BOOST_FOREACH( const AdapterType arrayItem, arr ) {
std::vector<std::string> newContext = context;
newContext.push_back("[" + boost::lexical_cast<std::string>(index) + "]");
ValidationVisitor<AdapterType> v(arrayItem,
newContext, strictTypes, results);
if (index >= constraint.itemSchemas.size()) {
if (constraint.additionalItemsSchema) {
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
if (results) {
results->pushError(context, "Failed to validate item #" +
boost::lexical_cast<std::string>(index) + " against additional items schema.");
validated = false;
} else {
return false;
}
constraint.applyToItemSubschemas(ValidateItems(arr, context,
results != NULL, strictTypes, results, &numValidated,
&validated));
if (!results && !validated) {
return false;
}
}
// Validate remaining items using 'additionalItems' sub-schema
if (numValidated < arrSize) {
if (additionalItemsSubschema) {
// Begin validation from the first item not validated against
// an sub-schema provided by the 'items' constraint
unsigned int index = numValidated;
typename AdapterType::Array::const_iterator begin = arr.begin();
begin.advance(numValidated);
for (typename AdapterType::Array::const_iterator itr = begin;
itr != arr.end(); ++itr) {
// Update context for current array item
std::vector<std::string> newContext = context;
newContext.push_back("[" +
boost::lexical_cast<std::string>(index) + "]");
ValidationVisitor<AdapterType> validator(*itr, newContext,
strictTypes, results);
if (!validator.validateSchema(*additionalItemsSubschema)) {
if (results) {
results->pushError(context,
"Failed to validate item #" +
boost::lexical_cast<std::string>(index) +
" against additional items schema.");
validated = false;
} else {
return false;
}
} else {
results->pushError(context, "Cannot validate item #" +
boost::lexical_cast<std::string>(index) + " in array due to missing schema.");
validated = false;
}
} else if (!v.validateSchema(*constraint.itemSchemas.at(index))) {
if (results) {
results->pushError(context, "Failed to validate item #" +
boost::lexical_cast<std::string>(index) + " against corresponding item schema.");
validated = false;
} else {
return false;
}
index++;
}
++index;
} else if (results) {
results->pushError(context, "Cannot validate item #" +
boost::lexical_cast<std::string>(numValidated) + " or "
"greater using 'items' constraint or 'additionalItems' "
"constraint.");
validated = false;
} else {
return false;
}
} else if (constraint.additionalItemsSchema) {
// Get access to the target as an object
const typename AdapterType::Array arr = target.asArray();
// Validate each item against additional items schema
unsigned int index = 0;
BOOST_FOREACH( const AdapterType arrayItem, arr ) {
std::vector<std::string> newContext = context;
newContext.push_back("[" + boost::lexical_cast<std::string>(index) + "]");
ValidationVisitor<AdapterType> v(arrayItem,
newContext, strictTypes, results);
if (!v.validateSchema(*constraint.additionalItemsSchema)) {
if (results) {
results->pushError(context, "Failed to validate item #" +
boost::lexical_cast<std::string>(index) + " against additional items schema.");
validated = false;
} else {
return false;
}
}
++index;
}
}
return validated;
@ -926,6 +902,65 @@ public:
return validated;
}
/**
* @brief Validate a value against a SingularItemsConstraint
*
* A SingularItemsConstraint represents an 'items' constraint that specifies
* a sub-schema against which all items in an array must validate. If the
* current value is not an array, validation always succeeds.
*
* @param constraint SingularItemsConstraint to validate against
*
* @returns \c true if validation is successful; \c false otherwise
*/
virtual bool visit(const SingularItemsConstraint &constraint)
{
// Ignore values that are not arrays
if (!target.isArray()) {
return true;
}
// Schema against which all items must validate
const Subschema *itemsSubschema = constraint.getItemsSubschema();
// Default items sub-schema accepts all values
if (!itemsSubschema) {
return true;
}
// Track whether validation has failed
bool validated = true;
unsigned int index = 0;
BOOST_FOREACH( const AdapterType &item, target.getArray() ) {
// Update context for current array item
std::vector<std::string> newContext = context;
newContext.push_back("[" +
boost::lexical_cast<std::string>(index) + "]");
// Create a validator for the current array item
ValidationVisitor<AdapterType> validationVisitor(item,
newContext, strictTypes, results);
// Perform validation
if (!validationVisitor.validateSchema(*itemsSubschema)) {
if (results) {
results->pushError(context,
"Failed to validate item #" +
boost::lexical_cast<std::string>(index) +
" in array.");
validated = false;
} else {
return false;
}
}
index++;
}
return validated;
}
/**
* @brief Validate against the type constraint represented by a
* TypeConstraint object.
@ -1089,6 +1124,78 @@ private:
bool * const validated;
};
/**
* @brief Functor to validate against sub-schemas in 'items' constraint
*/
struct ValidateItems
{
ValidateItems(
const typename AdapterType::Array &arr,
const std::vector<std::string> &context,
bool continueOnFailure,
bool strictTypes,
ValidationResults *results,
unsigned int *numValidated,
bool *validated)
: arr(arr),
context(context),
continueOnFailure(continueOnFailure),
strictTypes(strictTypes),
results(results),
numValidated(numValidated),
validated(validated) { }
bool operator()(unsigned int index, const Subschema *subschema) const
{
// Check that there are more elements to validate
if (index >= arr.size()) {
return false;
}
// Update context
std::vector<std::string> newContext = context;
newContext.push_back(
"[" + boost::lexical_cast<std::string>(index) + "]");
// Find array item
typename AdapterType::Array::const_iterator itr = arr.begin();
itr.advance(index);
// Validate current array item
ValidationVisitor validator(*itr, newContext, strictTypes, results);
if (validator.validateSchema(*subschema)) {
if (numValidated) {
(*numValidated)++;
}
return true;
}
if (validated) {
*validated = false;
}
if (results) {
results->pushError(newContext,
"Failed to validate item #" +
boost::lexical_cast<std::string>(index) +
" against corresponding item schema.");
}
return continueOnFailure;
}
private:
const typename AdapterType::Array &arr;
const std::vector<std::string> &context;
bool continueOnFailure;
bool strictTypes;
ValidationResults * const results;
unsigned int * const numValidated;
bool * const validated;
};
struct ValidateSchemaDependencies
{
ValidateSchemaDependencies(