Commit 01393e01 authored by miloyip's avatar miloyip

Add uniqueItems in schema

parent aeb5bda6
......@@ -171,7 +171,9 @@ template <typename SchemaDocumentType>
struct SchemaValidationContext {
typedef Schema<SchemaDocumentType> SchemaType;
typedef ISchemaValidatorFactory<SchemaType> SchemaValidatorFactoryType;
typedef Hasher<typename SchemaDocumentType::ValueType, typename SchemaDocumentType::AllocatorType> HasherType;
typedef GenericValue<UTF8<>, CrtAllocator> HashCodeArray;
typedef typename SchemaType::ValueType ValueType;
typedef Hasher<ValueType, typename SchemaDocumentType::AllocatorType> HasherType;
enum PatternValidatorType {
kPatternValidatorOnly,
......@@ -191,8 +193,9 @@ struct SchemaValidationContext {
SizeType count;
};
SchemaValidationContext(const SchemaValidatorFactoryType* f, const SchemaType* s) :
SchemaValidationContext(const SchemaValidatorFactoryType* f, CrtAllocator* a, const SchemaType* s) :
factory(f),
allocator(a),
schema(s),
valueSchema(),
hasher(),
......@@ -202,7 +205,9 @@ struct SchemaValidationContext {
patternPropertiesSchemaCount(),
valuePatternValidatorType(kPatternValidatorOnly),
objectDependencies(),
inArray(false)
inArray(false),
valueUniqueness(false),
arrayUniqueness(false)
{
}
......@@ -215,6 +220,7 @@ struct SchemaValidationContext {
}
const SchemaValidatorFactoryType* factory;
CrtAllocator* allocator; // For allocating memory for context
const SchemaType* schema;
const SchemaType* valueSchema;
HasherType* hasher;
......@@ -229,10 +235,13 @@ struct SchemaValidationContext {
SizeType patternPropertiesSchemaCount;
PatternValidatorType valuePatternValidatorType;
PatternValidatorType objectPatternValidatorType;
HashCodeArray arrayElementHashCodes; // array of uint64_t
SizeType objectRequiredCount;
SizeType arrayElementIndex;
bool* objectDependencies;
bool inArray;
bool valueUniqueness;
bool arrayUniqueness;
};
///////////////////////////////////////////////////////////////////////////////
......@@ -275,6 +284,7 @@ public:
minItems_(),
maxItems_(SizeType(~0)),
additionalItems_(true),
uniqueItems_(false),
pattern_(),
minLength_(0),
maxLength_(~SizeType(0)),
......@@ -447,6 +457,8 @@ public:
additionalItemsSchema_ = document->CreateSchema(p.Append("additionalItems"), *v);
}
AssignIfExist(uniqueItems_, value, "uniqueItems");
// String
AssignIfExist(minLength_, value, "minLength");
AssignIfExist(maxLength_, value, "maxLength");
......@@ -489,6 +501,9 @@ public:
bool BeginValue(Context& context) const {
if (context.inArray) {
if (uniqueItems_)
context.valueUniqueness = true;
if (itemsList_)
context.valueSchema = itemsList_;
else if (itemsTuple_) {
......@@ -730,7 +745,10 @@ public:
CreateParallelValidator(context);
if ((type_ & (1 << kArraySchemaType)) == 0)
return false;
if (uniqueItems_)
context.arrayElementHashCodes.SetArray();
context.arrayElementIndex = 0;
context.inArray = true;
return true;
......@@ -848,7 +866,7 @@ private:
}
void CreateParallelValidator(Context& context) const {
if (enum_)
if (enum_ || context.arrayUniqueness)
context.hasher = new HasherType;
if (allOf_.schemas) CreateSchemaValidators(context, context.allOfValidators, allOf_);
if (anyOf_.schemas) CreateSchemaValidators(context, context.anyOfValidators, anyOf_);
......@@ -956,6 +974,7 @@ private:
SizeType minItems_;
SizeType maxItems_;
bool additionalItems_;
bool uniqueItems_;
const RegexType* pattern_;
SizeType minLength_;
......@@ -1282,7 +1301,7 @@ private:
SizeType count = CurrentContext().patternPropertiesSchemaCount;
const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
bool valueUniqueness = CurrentContext().valueUniqueness;
if (CurrentContext().valueSchema)
PushSchema(*CurrentContext().valueSchema);
......@@ -1293,6 +1312,8 @@ private:
for (SizeType i = 0; i < count; i++)
va.validators[va.count++] = CreateSchemaValidator(*sa[i]);
}
CurrentContext().arrayUniqueness = valueUniqueness;
}
return true;
}
......@@ -1301,11 +1322,24 @@ private:
if (!CurrentSchema().EndValue(CurrentContext()))
return false;
uint64_t h = CurrentContext().arrayUniqueness ? CurrentContext().hasher->GetHashCode() : 0;
PopSchema();
if (!schemaStack_.Empty()) {
Context& context = CurrentContext();
if (context.valueUniqueness) {
for (typename Context::HashCodeArray::ConstValueIterator itr = context.arrayElementHashCodes.Begin(); itr != context.arrayElementHashCodes.End(); ++itr)
if (itr->GetUint64() == h)
return false;
context.arrayElementHashCodes.PushBack(h, *context.allocator);
}
}
return true;
}
void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(this, &schema); }
void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(this, &contextAllocator_, &schema); }
void PopSchema() { schemaStack_.template Pop<Context>(1)->~Context(); }
const SchemaType& CurrentSchema() { return *schemaStack_.template Top<Context>()->schema; }
Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
......@@ -1315,6 +1349,7 @@ private:
const SchemaType& root_;
BaseReaderHandler<EncodingType> nullOutputHandler_;
OutputHandler& outputHandler_;
CrtAllocator contextAllocator_;
internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
//internal::Stack<Allocator> documentStack_; //!< stack to store the current path of validating document (Value *)
bool valid_;
......
......@@ -664,17 +664,15 @@ TEST(SchemaValidator, Array_ItemsRange) {
VALIDATE(s, "[1, 2, 3, 4]", false);
}
#if 0
// TODO
TEST(SchemaValidator, Array_Uniqueness) {
TEST(SchemaValidator, Array_UniqueItems) {
Document sd;
sd.Parse("{\"type\": \"array\", \"uniqueItems\": true}");
SchemaDocument s(sd);
VALIDATE(s, "[1, 2, 3, 4, 5]", true);
VALIDATE(s, "[1, 2, 3, 4, 5]", false);
VALIDATE(s, "[1, 2, 3, 3, 4]", false);
VALIDATE(s, "[]", true);
}
#endif
TEST(SchemaValidator, Boolean) {
Document sd;
......@@ -885,7 +883,7 @@ TEST(SchemaValidator, TestSuite) {
"refRemote.json",
"required.json",
"type.json",
//"uniqueItems.json"
"uniqueItems.json"
};
const char* onlyRunDescription = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment