Update OneOfConstraint to use custom allocator, with better encapsulation

This commit is contained in:
Tristan Penman 2015-12-27 22:02:23 +11:00
parent d534c49393
commit c53268ba77
5 changed files with 97 additions and 63 deletions

View File

@ -434,15 +434,40 @@ struct NotConstraint: BasicConstraint<NotConstraint>
/**
* @brief Represents a 'oneOf' constraint.
*/
struct OneOfConstraint: BasicConstraint<OneOfConstraint>
class OneOfConstraint: public BasicConstraint<OneOfConstraint>
{
typedef std::vector<const Subschema *> Schemas;
public:
OneOfConstraint()
: subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
OneOfConstraint(const Schemas &schemas)
: schemas(schemas) { }
OneOfConstraint(CustomAlloc allocFn, CustomFree freeFn)
: BasicConstraint(allocFn, freeFn),
subschemas(Allocator::rebind<const Subschema *>::other(allocator)) { }
/// Collection of schemas that must all be satisfied
const Schemas schemas;
void addSubschema(const Subschema *subschema)
{
subschemas.push_back(subschema);
}
template<typename FunctorType>
void applyToSubschemas(const FunctorType &fn) const
{
unsigned int index = 0;
BOOST_FOREACH( const Subschema *subschema, subschemas ) {
if (!fn(index, subschema)) {
return;
}
index++;
}
}
private:
typedef std::vector<const Subschema *,
internal::CustomAllocator<const Subschema *> > Subschemas;
/// Collection of sub-schemas, exactly one of which must be satisfied
Subschemas subschemas;
};
/**

View File

@ -5,8 +5,6 @@
namespace valijson {
namespace constraints {
struct AllOfConstraint;
struct AnyOfConstraint;
struct EnumConstraint;
struct ItemsConstraint;
struct FormatConstraint;
@ -20,14 +18,16 @@ struct MinLengthConstraint;
struct MinPropertiesConstraint;
struct MultipleOfConstraint;
struct NotConstraint;
struct OneOfConstraint;
struct PatternConstraint;
struct PropertiesConstraint;
struct RequiredConstraint;
struct TypeConstraint;
struct UniqueItemsConstraint;
class AllOfConstraint;
class AnyOfConstraint;
class DependenciesConstraint;
class OneOfConstraint;
/// Interface to allow usage of the visitor pattern with Constraints
class ConstraintVisitor

View File

@ -1152,18 +1152,20 @@ private:
const boost::optional<
typename FetchDocumentFunction<AdapterType>::Type > fetchDoc)
{
constraints::OneOfConstraint::Schemas childSchemas;
constraints::OneOfConstraint constraint;
int index = 0;
BOOST_FOREACH ( const AdapterType schemaNode, node.getArray() ) {
const std::string childPath = nodePath + "/" +
boost::lexical_cast<std::string>(index);
childSchemas.push_back(rootSchema.createSubschema());
const Subschema *subschema = rootSchema.createSubschema();
constraint.addSubschema(subschema);
populateSchema<AdapterType>(rootSchema, rootNode, schemaNode,
*childSchemas.back(), currentScope, childPath, fetchDoc);
*subschema, currentScope, childPath, fetchDoc);
index++;
}
return constraints::OneOfConstraint(childSchemas);
return constraint;
}
/**

View File

@ -114,8 +114,8 @@ public:
{
bool validated = true;
constraint.applyToSubschemas(ValidateAllSubschemas(target, context,
*this, results, &validated));
constraint.applyToSubschemas(ValidateSubschemas(target, context,
false, *this, results, NULL, &validated));
return validated;
}
@ -739,15 +739,12 @@ public:
virtual bool visit(const OneOfConstraint &constraint)
{
unsigned int numValidated = 0;
ValidationResults newResults;
ValidationResults *childResults = (results) ? &newResults : NULL;
BOOST_FOREACH( const Subschema *subschema, constraint.schemas ) {
ValidationVisitor<AdapterType> v(target, context, strictTypes, childResults);
if (v.validateSchema(*subschema)) {
numValidated++;
}
}
constraint.applyToSubschemas(ValidateSubschemas(target, context,
true, *this, childResults, &numValidated, NULL));
if (numValidated == 0) {
if (results) {
@ -1044,47 +1041,6 @@ public:
private:
struct ValidateAllSubschemas
{
ValidateAllSubschemas(
const AdapterType &adapter,
const std::vector<std::string> &context,
ValidationVisitor &validationVisitor,
ValidationResults *results,
bool *validated)
: adapter(adapter),
context(context),
validationVisitor(validationVisitor),
results(results),
validated(validated) { }
bool operator()(unsigned int index, const Subschema *subschema) const
{
if (!validationVisitor.validateSchema(*subschema)) {
if (validated) {
*validated = false;
}
if (results) {
results->pushError(context,
"Failed to validate against child schema #" +
boost::lexical_cast<std::string>(index) +
" of allOf constraint.");
}
return false;
}
return true;
}
private:
const AdapterType &adapter;
const std::vector<std::string> &context;
ValidationVisitor &validationVisitor;
ValidationResults * const results;
bool * const validated;
};
struct ValidateAtLeastOneSubschema
{
ValidateAtLeastOneSubschema(
@ -1215,6 +1171,57 @@ private:
bool * const validated;
};
struct ValidateSubschemas
{
ValidateSubschemas(
const AdapterType &adapter,
const std::vector<std::string> &context,
bool continueOnFailure,
ValidationVisitor &validationVisitor,
ValidationResults *results,
unsigned int *numValidated,
bool *validated)
: adapter(adapter),
context(context),
continueOnFailure(continueOnFailure),
validationVisitor(validationVisitor),
results(results),
numValidated(numValidated),
validated(validated) { }
bool operator()(unsigned int index, const Subschema *subschema) const
{
if (validationVisitor.validateSchema(*subschema)) {
if (numValidated) {
(*numValidated)++;
}
return true;
}
if (validated) {
*validated = false;
}
if (results) {
results->pushError(context,
"Failed to validate against child schema #" +
boost::lexical_cast<std::string>(index) + ".");
}
return continueOnFailure;
}
private:
const AdapterType &adapter;
const std::vector<std::string> &context;
bool continueOnFailure;
ValidationVisitor &validationVisitor;
ValidationResults * const results;
unsigned int * const numValidated;
bool * const validated;
};
/**
* @brief Callback function that passes a visitor to a constraint.
*

View File

@ -88,7 +88,7 @@ TEST_F(TestValidationErrors, AllOfConstraintFailure)
EXPECT_TRUE( results.popError(error) );
EXPECT_EQ( 1, error.context.size() );
EXPECT_EQ( "<root>", error.context[0] );
EXPECT_EQ( "Failed to validate against child schema #0 of allOf constraint.", error.description );
EXPECT_EQ( "Failed to validate against child schema #0.", error.description );
EXPECT_FALSE( results.popError(error) );