Commit 01393e01 authored by miloyip's avatar miloyip

Add uniqueItems in schema

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