Update RequiredConstraint to use custom allocator, with better encapsulation

This commit is contained in:
Tristan Penman 2015-12-30 07:58:54 +11:00
parent a0e1a2f74a
commit 05ba5bf711
5 changed files with 101 additions and 30 deletions

View File

@ -158,11 +158,11 @@ void addRequiredConstraint(Schema &schema)
{ {
// Add a RequiredConstraint to the schema, specifying that the category, // Add a RequiredConstraint to the schema, specifying that the category,
// price, and title properties must be present. // price, and title properties must be present.
RequiredConstraint::RequiredProperties requiredProperties; RequiredConstraint constraint;
requiredProperties.insert("category"); constraint.addRequiredProperty("category");
requiredProperties.insert("price"); constraint.addRequiredProperty("price");
requiredProperties.insert("title"); constraint.addRequiredProperty("title");
schema.addConstraint(RequiredConstraint(requiredProperties)); schema.addConstraint(constraint);
} }
void addTypeConstraint(Schema &schema) void addTypeConstraint(Schema &schema)

View File

@ -552,17 +552,44 @@ struct PropertiesConstraint: BasicConstraint<PropertiesConstraint> {
/** /**
* @brief Represents a 'required' constraint. * @brief Represents a 'required' constraint.
*/ */
struct RequiredConstraint: BasicConstraint<RequiredConstraint> class RequiredConstraint: public BasicConstraint<RequiredConstraint>
{ {
typedef std::set<std::string> RequiredProperties; public:
RequiredConstraint()
: requiredProperties(std::less<String>(), allocator) { }
RequiredConstraint(const RequiredProperties &requiredProperties) RequiredConstraint(CustomAlloc allocFn, CustomFree freeFn)
: requiredProperties(requiredProperties) : BasicConstraint(allocFn, freeFn),
requiredProperties(std::less<String>(), allocator) { }
bool addRequiredProperty(const char *propertyName)
{ {
return requiredProperties.insert(String(propertyName,
Allocator::rebind<char>::other(allocator))).second;
} }
const RequiredProperties requiredProperties; template<typename AllocatorType>
bool addRequiredProperty(const std::basic_string<char,
std::char_traits<char>, AllocatorType> &propertyName)
{
return addRequiredProperty(propertyName.c_str());
}
template<typename FunctorType>
void applyToRequiredProperties(const FunctorType &fn) const
{
BOOST_FOREACH( const String &propertyName, requiredProperties ) {
if (!fn(propertyName)) {
return;
}
}
}
private:
typedef std::set<String, std::less<String>,
internal::CustomAllocator<String> > RequiredProperties;
RequiredProperties requiredProperties;
}; };
/** /**

View File

@ -19,13 +19,14 @@ struct MultipleOfConstraint;
struct NotConstraint; struct NotConstraint;
struct PatternConstraint; struct PatternConstraint;
struct PropertiesConstraint; struct PropertiesConstraint;
struct RequiredConstraint;
class AllOfConstraint; class AllOfConstraint;
class AnyOfConstraint; class AnyOfConstraint;
class DependenciesConstraint; class DependenciesConstraint;
class LinearItemsConstraint; class LinearItemsConstraint;
class OneOfConstraint; class OneOfConstraint;
class RequiredConstraint;
class SingularItemsConstraint; class SingularItemsConstraint;
class TypeConstraint; class TypeConstraint;
class UniqueItemsConstraint; class UniqueItemsConstraint;

View File

@ -1372,9 +1372,9 @@ private:
} }
if (node.asBool()) { if (node.asBool()) {
constraints::RequiredConstraint::RequiredProperties requiredProperties; constraints::RequiredConstraint constraint;
requiredProperties.insert(name); constraint.addRequiredProperty(name);
return constraints::RequiredConstraint(requiredProperties); return constraint;
} }
return boost::none; return boost::none;
@ -1395,15 +1395,18 @@ private:
constraints::RequiredConstraint makeRequiredConstraint( constraints::RequiredConstraint makeRequiredConstraint(
const AdapterType &node) const AdapterType &node)
{ {
constraints::RequiredConstraint::RequiredProperties requiredProperties; constraints::RequiredConstraint constraint;
BOOST_FOREACH( const AdapterType v, node.getArray() ) { BOOST_FOREACH( const AdapterType v, node.getArray() ) {
if (!v.isString()) { if (!v.isString()) {
// @todo throw exception throw std::runtime_error("Expected required property name to "
"be a string value");
} }
requiredProperties.insert(v.getString());
constraint.addRequiredProperty(v.getString());
} }
return constraints::RequiredConstraint(requiredProperties); return constraint;
} }
/** /**

View File

@ -887,23 +887,16 @@ public:
{ {
if ((strictTypes && !target.isObject()) || !target.maybeObject()) { if ((strictTypes && !target.isObject()) || !target.maybeObject()) {
if (results) { if (results) {
results->pushError(context, "Object required to validate 'required' properties."); results->pushError(context,
"Object required to validate 'required' properties.");
} }
return false; return false;
} }
bool validated = true; bool validated = true;
const typename AdapterType::Object object = target.asObject(); const typename AdapterType::Object object = target.asObject();
BOOST_FOREACH( const std::string &requiredProperty, constraint.requiredProperties ) { constraint.applyToRequiredProperties(ValidateProperties(object, context,
if (object.find(requiredProperty) == object.end()) { true, results != NULL, results, &validated));
if (results) {
results->pushError(context, "Missing required property '" + requiredProperty + "'.");
validated = false;
} else {
return false;
}
}
}
return validated; return validated;
} }
@ -1053,6 +1046,53 @@ public:
private: private:
/**
* @brief Functor to validate the presence of a set of properties
*/
struct ValidateProperties
{
ValidateProperties(
const typename AdapterType::Object &object,
const std::vector<std::string> &context,
bool continueOnSuccess,
bool continueOnFailure,
ValidationResults *results,
bool *validated)
: object(object),
context(context),
continueOnSuccess(continueOnSuccess),
continueOnFailure(continueOnFailure),
results(results),
validated(validated) { }
template<typename StringType>
bool operator()(const StringType &property) const
{
if (object.find(property.c_str()) == object.end()) {
if (validated) {
*validated = false;
}
if (results) {
results->pushError(context, "Missing required property '" +
std::string(property.c_str()) + "'.");
}
return continueOnFailure;
}
return continueOnSuccess;
}
private:
const typename AdapterType::Object &object;
const std::vector<std::string> &context;
bool continueOnSuccess;
bool continueOnFailure;
ValidationResults * const results;
bool * const validated;
};
/** /**
* @brief Functor to validate property-based dependencies * @brief Functor to validate property-based dependencies
*/ */