Update EnumConstraint to use custom allocator for collection (but not frozen values)

This commit is contained in:
Tristan Penman 2016-01-02 10:27:52 +11:00
parent 99a5c2f604
commit f779b0780c
6 changed files with 116 additions and 47 deletions

View File

@ -95,16 +95,15 @@ void addPropertiesConstraint(Schema &schema)
{
// Prepare an enum constraint requires a document to be equal to at
// least one of a set of possible values
EnumConstraint::Values enumConstraintValues;
enumConstraintValues.push_back(new RapidJsonFrozenValue("album"));
enumConstraintValues.push_back(new RapidJsonFrozenValue("book"));
enumConstraintValues.push_back(new RapidJsonFrozenValue("other"));
enumConstraintValues.push_back(new RapidJsonFrozenValue("video"));
EnumConstraint constraint;
constraint.addValue(RapidJsonFrozenValue("album"));
constraint.addValue(RapidJsonFrozenValue("book"));
constraint.addValue(RapidJsonFrozenValue("other"));
constraint.addValue(RapidJsonFrozenValue("video"));
// Create a subschema, owned by the root schema, with a constraint
const Subschema *subschema = schema.createSubschema();
schema.addConstraintToSubschema(EnumConstraint(enumConstraintValues),
subschema);
schema.addConstraintToSubschema(constraint, subschema);
// Include subschema in properties constraint
propertySchemaMap["category"] = subschema;

View File

@ -50,19 +50,6 @@ public:
};
/**
* @brief Implementation of new_clone for the FrozenValue interface, as
* required for the boost pointer containers.
*
* @param frozenValue reference to FrozenValue to clone
*
* @returns a pointer to a new FrozenValue, belonging to the caller
*/
inline FrozenValue * new_clone(const FrozenValue &frozenValue)
{
return frozenValue.clone();
}
} // namespace adapters
} // namespace valijson

View File

@ -231,20 +231,51 @@ private:
};
/**
* @brief Represents an 'enum' constraint.
* @brief Represents an 'enum' constraint
*
* An enum constraint provides a set of permissible values for a JSON node. The
* node will only validate against this constraint if it matches one of the
* values in the set.
* An enum constraint provides a collection of permissible values for a JSON
* node. The node will only validate against this constraint if it matches one
* or more of the values in the collection.
*/
struct EnumConstraint: BasicConstraint<EnumConstraint>
class EnumConstraint: public BasicConstraint<EnumConstraint>
{
typedef boost::ptr_vector<adapters::FrozenValue> Values;
public:
EnumConstraint()
: enumValues(Allocator::rebind<const EnumValue *>::other(allocator)) { }
EnumConstraint(const Values &values) // Copy each of the frozen values
: values(values) { }
EnumConstraint(CustomAlloc allocFn, CustomFree freeFn)
: BasicConstraint(allocFn, freeFn),
enumValues(Allocator::rebind<const EnumValue *>::other(allocator)) { }
const Values values;
void addValue(const adapters::Adapter &value)
{
// TODO: Freeze value using custom alloc/free functions
enumValues.push_back(value.freeze());
}
void addValue(const adapters::FrozenValue &value)
{
// TODO: Clone using custom alloc/free functions
enumValues.push_back(value.clone());
}
template<typename FunctorType>
void applyToValues(const FunctorType &fn) const
{
BOOST_FOREACH( const EnumValue *value, enumValues ) {
if (!fn(*value)) {
return;
}
}
}
private:
typedef adapters::FrozenValue EnumValue;
typedef std::vector<const EnumValue *,
internal::CustomAllocator<const EnumValue *> > EnumValues;
EnumValues enumValues;
};
/**

View File

@ -5,7 +5,7 @@
namespace valijson {
namespace constraints {
struct EnumConstraint;
struct FormatConstraint;
struct MaximumConstraint;
struct MaxItemsConstraint;
@ -22,6 +22,7 @@ struct PropertiesConstraint;
class AllOfConstraint;
class AnyOfConstraint;
class DependenciesConstraint;
class EnumConstraint;
class LinearItemsConstraint;
class NotConstraint;
class OneOfConstraint;

View File

@ -697,16 +697,16 @@ private:
const AdapterType &node)
{
// Make a copy of each value in the enum array
constraints::EnumConstraint::Values values;
constraints::EnumConstraint constraint;
BOOST_FOREACH( const AdapterType value, node.getArray() ) {
values.push_back(value.freeze());
constraint.addValue(value);
}
/// @todo This will make another copy of the values while constructing
/// the EnumConstraint. Move semantics in C++11 should make it possible
/// to avoid these copies without complicating the implementation of the
/// EnumConstraint class.
return constraints::EnumConstraint(values);
return constraint;
}
/**

View File

@ -205,30 +205,31 @@ public:
}
/**
* @brief Validate against the enum constraint represented by an
* EnumConstraint object.
* @brief Validate current node against an EnumConstraint
*
* Validation succeeds if the target is equal to one of the values provided
* by the enum constraint.
* by the EnumConstraint.
*
* @param constraint Constraint that the target must validate against.
* @param constraint Constraint that the target must validate against
*
* @return true if validation succeeds, false otherwise.
* @return \c true if validation succeeds; \c false otherwise
*/
virtual bool visit(const EnumConstraint &constraint)
{
// Compare the target with each 'frozen' value in the enum constraint.
BOOST_FOREACH( const adapters::FrozenValue &value, constraint.values ) {
if (value.equalTo(target, true)) {
return true;
unsigned int numValidated = 0;
constraint.applyToValues(ValidateEquality(target, context, false, true,
strictTypes, NULL, &numValidated));
if (numValidated == 0) {
if (results) {
results->pushError(context,
"Failed to match against any enum values.");
}
return false;
}
if (results) {
results->pushError(context, "Failed to match against any enum values.");
}
return false;
return numValidated > 0;
}
/**
@ -1057,6 +1058,56 @@ public:
private:
/**
* @brief Functor to compare a node with a collection of values
*/
struct ValidateEquality
{
ValidateEquality(
const AdapterType &target,
const std::vector<std::string> &context,
bool continueOnSuccess,
bool continueOnFailure,
bool strictTypes,
ValidationResults *results,
unsigned int *numValidated)
: target(target),
context(context),
continueOnSuccess(continueOnSuccess),
continueOnFailure(continueOnFailure),
strictTypes(strictTypes),
results(results),
numValidated(numValidated) { }
template<typename OtherValue>
bool operator()(const OtherValue &value) const
{
if (value.equalTo(target, strictTypes)) {
if (numValidated) {
(*numValidated)++;
}
return continueOnSuccess;
}
if (results) {
results->pushError(context,
"Target value and comparison value are not equal");
}
return continueOnFailure;
}
private:
const AdapterType &target;
const std::vector<std::string> &context;
bool continueOnSuccess;
bool continueOnFailure;
bool strictTypes;
ValidationResults * const results;
unsigned int * const numValidated;
};
/**
* @brief Functor to validate the presence of a set of properties
*/