From 24f060f7cbcba1bccaadadfb5e521bf0928e1335 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 8 May 2015 18:39:26 +0800 Subject: [PATCH] Refactor template parameters and add ISchemaValidator --- include/rapidjson/schema.h | 232 ++++++++++++++++++++-------------- test/unittest/pointertest.cpp | 6 + 2 files changed, 141 insertions(+), 97 deletions(-) diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 4d90e22..a900c3d 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -16,6 +16,7 @@ #define RAPIDJSON_SCHEMA_H_ #include "document.h" +#include "pointer.h" #include // HUGE_VAL, abs, floor #if !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) @@ -41,7 +42,7 @@ RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_NAMESPACE_BEGIN -enum SchemaType { +enum SchemaValueType { kNullSchemaType, kBooleanSchemaType, kObjectSchemaType, @@ -52,13 +53,28 @@ enum SchemaType { kTotalSchemaType }; -template +template class Schema; -template +template +class GenericSchemaDocument; + +template class GenericSchemaValidator; -template +class ISchemaValidator { +public: + virtual ~ISchemaValidator() {} + virtual bool IsValid() const = 0; +}; + +template +class ISchemaValidatorFactory { +public: + virtual ~ISchemaValidatorFactory() {} + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) const = 0; +}; + struct SchemaValidatorArray { SchemaValidatorArray() : validators(), count() {} ~SchemaValidatorArray() { @@ -67,11 +83,11 @@ struct SchemaValidatorArray { delete[] validators; } - GenericSchemaValidator, CrtAllocator>** validators; + ISchemaValidator** validators; SizeType count; }; -template +template struct SchemaArray { SchemaArray() : schemas(), count() {} ~SchemaArray() { @@ -80,7 +96,7 @@ struct SchemaArray { delete[] schemas; } - Schema** schemas; + Schema** schemas; SizeType count; }; @@ -90,9 +106,14 @@ enum PatternValidatorType { kPatternValidatorWithAdditionalProperty }; -template +template struct SchemaValidationContext { - SchemaValidationContext(const Schema* s) : + typedef Schema SchemaType; + typedef GenericSchemaValidator, CrtAllocator> SchemaValidatorType; + typedef ISchemaValidatorFactory SchemaValidatorFactoryType; + + SchemaValidationContext(const SchemaValidatorFactoryType* f, const SchemaType* s) : + factory(f), schema(s), valueSchema(), patternPropertiesSchemas(), @@ -110,15 +131,16 @@ struct SchemaValidationContext { delete[] objectDependencies; } - const Schema* schema; - const Schema* valueSchema; - SchemaValidatorArray allOfValidators; - SchemaValidatorArray anyOfValidators; - SchemaValidatorArray oneOfValidators; - SchemaValidatorArray dependencyValidators; - SchemaValidatorArray patternPropertiesValidators; - const Schema** patternPropertiesSchemas; - GenericSchemaValidator, CrtAllocator>* notValidator; + const SchemaValidatorFactoryType* factory; + const SchemaType* schema; + const SchemaType* valueSchema; + SchemaValidatorArray allOfValidators; + SchemaValidatorArray anyOfValidators; + SchemaValidatorArray oneOfValidators; + SchemaValidatorArray dependencyValidators; + SchemaValidatorArray patternPropertiesValidators; + const SchemaType** patternPropertiesSchemas; + ISchemaValidator* notValidator; SizeType patternPropertiesSchemaCount; PatternValidatorType valuePatternValidatorType; PatternValidatorType objectPatternValidatorType; @@ -128,14 +150,19 @@ struct SchemaValidationContext { bool inArray; }; -template +template class Schema { public: + typedef Encoding EncodingType; typedef typename Encoding::Ch Ch; - typedef SchemaValidationContext Context; + typedef SchemaValidationContext Context; + typedef GenericSchemaDocument SchemaDocumentType; + typedef Schema SchemaType; + typedef GenericValue ValueType; + typedef GenericPointer PointerType; template - Schema(const ValueType& value) : + Schema(SchemaDocumentType* document, const PointerType& p, const ValueType& value) : not_(), type_((1 << kTotalSchemaType) - 1), // typeless properties_(), @@ -185,12 +212,12 @@ public: if (v->IsArray() && v->Size() > 0) enum_.CopyFrom(*v, allocator_); - AssigIfExist(allOf_, value, "allOf"); - AssigIfExist(anyOf_, value, "anyOf"); - AssigIfExist(oneOf_, value, "oneOf"); + AssigIfExist(allOf_, document, p, value, "allOf"); + AssigIfExist(anyOf_, document, p, value, "anyOf"); + AssigIfExist(oneOf_, document, p, value, "oneOf"); if (const ValueType* v = GetMember(value, "not")) - not_ = new Schema(*v); + not_ = document->CreateSchema(p, *v); // Object @@ -233,7 +260,7 @@ public: for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { SizeType index; if (FindPropertyIndex(itr->name, &index)) { - properties_[index].schema = new Schema(itr->value); + properties_[index].schema = document->CreateSchema(p, itr->value); properties_[index].typeless = false; } } @@ -244,7 +271,7 @@ public: for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); - patternProperties_[patternPropertyCount_].schema = new Schema(itr->value); + patternProperties_[patternPropertyCount_].schema = document->CreateSchema(p, itr->value); patternPropertyCount_++; } } @@ -275,7 +302,7 @@ public: } else if (itr->value.IsObject()) { hasSchemaDependencies_ = true; - properties_[sourceIndex].dependenciesSchema = new Schema(itr->value); + properties_[sourceIndex].dependenciesSchema = document->CreateSchema(p, itr->value); } } } @@ -285,7 +312,7 @@ public: if (v->IsBool()) additionalProperties_ = v->GetBool(); else if (v->IsObject()) - additionalPropertiesSchema_ = new Schema(*v); + additionalPropertiesSchema_ = document->CreateSchema(p, *v); } AssignIfExist(minProperties_, value, "minProperties"); @@ -294,11 +321,11 @@ public: // Array if (const ValueType* v = GetMember(value, "items")) { if (v->IsObject()) // List validation - itemsList_ = new Schema(*v); + itemsList_ = document->CreateSchema(p, *v); else if (v->IsArray()) { // Tuple validation - itemsTuple_ = new Schema*[v->Size()]; + itemsTuple_ = new Schema*[v->Size()]; for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) - itemsTuple_[itemsTupleCount_++] = new Schema(*itr); + itemsTuple_[itemsTupleCount_++] = document->CreateSchema(p, *itr); } } @@ -309,7 +336,7 @@ public: if (v->IsBool()) additionalItems_ = v->GetBool(); else if (v->IsObject()) - additionalItemsSchema_ = new Schema(*v); + additionalItemsSchema_ = document->CreateSchema(p, *v); } // String @@ -521,9 +548,9 @@ public: if (patternProperties_) { // pre-allocate schema array SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType - context.patternPropertiesSchemas = new const Schema*[count]; + context.patternPropertiesSchemas = new const SchemaType*[count]; context.patternPropertiesSchemaCount = 0; - std::memset(context.patternPropertiesSchemas, 0, sizeof(Schema*) * count); + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); } return true; @@ -539,7 +566,7 @@ public: SizeType index; if (FindPropertyIndex(str, len, &index)) { - const Schema* propertySchema = properties_[index].typeless ? GetTypeless() : properties_[index].schema; + const SchemaType* propertySchema = properties_[index].typeless ? GetTypeless() : properties_[index].schema; if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = propertySchema; context.valueSchema = GetTypeless(); @@ -619,8 +646,11 @@ private: #endif typedef GenericSchemaValidator, CrtAllocator> SchemaValidatorType; - static const Schema* GetTypeless() { - static Schema typeless(Value(kObjectType).Move()); + typedef SchemaArray SchemaArrayType; + typedef SchemaValidatorArray SchemaValidatorArrayType; + + static const SchemaType* GetTypeless() { + static SchemaType typeless(0, PointerType(), Value(kObjectType).Move()); return &typeless; } @@ -653,15 +683,15 @@ private: out = static_cast(v->GetUint64()); } - template - static void AssigIfExist(SchemaArray& out, const ValueType& value, const char* name) { + template + static void AssigIfExist(SchemaArrayType& out, const DocumentType& document, const PointerType& p, const ValueType& value, const char* name) { if (const ValueType* v = GetMember(value, name)) if (v->IsArray() && v->Size() > 0) { out.count = v->Size(); out.schemas = new Schema*[out.count]; memset(out.schemas, 0, sizeof(Schema*)* out.count); for (SizeType i = 0; i < out.count; i++) - out.schemas[i] = new Schema((*v)[i]); + out.schemas[i] = document->CreateSchema(p, (*v)[i]); } } @@ -706,26 +736,26 @@ private: } void CreateParallelValidator(Context& context) const { - if (allOf_.schemas) CreateSchemaValidators(context.allOfValidators, allOf_); - if (anyOf_.schemas) CreateSchemaValidators(context.anyOfValidators, anyOf_); - if (oneOf_.schemas) CreateSchemaValidators(context.oneOfValidators, oneOf_); + if (allOf_.schemas) CreateSchemaValidators(context, context.allOfValidators, allOf_); + if (anyOf_.schemas) CreateSchemaValidators(context, context.anyOfValidators, anyOf_); + if (oneOf_.schemas) CreateSchemaValidators(context, context.oneOfValidators, oneOf_); if (not_ && !context.notValidator) - context.notValidator = new SchemaValidatorType(*not_); + context.notValidator = context.factory->CreateSchemaValidator(*not_); if (hasSchemaDependencies_ && !context.dependencyValidators.validators) { - context.dependencyValidators.validators = new SchemaValidatorType*[propertyCount_]; + context.dependencyValidators.validators = new ISchemaValidator*[propertyCount_]; context.dependencyValidators.count = propertyCount_; for (SizeType i = 0; i < propertyCount_; i++) - context.dependencyValidators.validators[i] = properties_[i].dependenciesSchema ? new SchemaValidatorType(*properties_[i].dependenciesSchema) : 0; + context.dependencyValidators.validators[i] = properties_[i].dependenciesSchema ? context.factory->CreateSchemaValidator(*properties_[i].dependenciesSchema) : 0; } } - void CreateSchemaValidators(SchemaValidatorArray& validators, const SchemaArray& schemas) const { + void CreateSchemaValidators(Context& context, SchemaValidatorArrayType& validators, const SchemaArrayType& schemas) const { if (!validators.validators) { - validators.validators = new SchemaValidatorType*[schemas.count]; + validators.validators = new ISchemaValidator*[schemas.count]; validators.count = schemas.count; for (SizeType i = 0; i < schemas.count; i++) - validators.validators[i] = new SchemaValidatorType(*schemas.schemas[i]); + validators.validators[i] = context.factory->CreateSchemaValidator(*schemas.schemas[i]); } } @@ -772,8 +802,8 @@ private: } GenericValue name; - const Schema* schema; - const Schema* dependenciesSchema; + const SchemaType* schema; + const SchemaType* dependenciesSchema; bool* dependencies; bool required; bool typeless; @@ -786,20 +816,20 @@ private: delete pattern; } - Schema* schema; + SchemaType* schema; RegexType* pattern; }; - MemoryPoolAllocator<> allocator_; + Allocator allocator_; GenericValue enum_; - SchemaArray allOf_; - SchemaArray anyOf_; - SchemaArray oneOf_; - Schema* not_; + SchemaArrayType allOf_; + SchemaArrayType anyOf_; + SchemaArrayType oneOf_; + SchemaType* not_; unsigned type_; // bitmask of kSchemaType Property* properties_; - Schema* additionalPropertiesSchema_; + SchemaType* additionalPropertiesSchema_; PatternProperty* patternProperties_; SizeType patternPropertyCount_; SizeType propertyCount_; @@ -810,9 +840,9 @@ private: bool hasDependencies_; bool hasSchemaDependencies_; - Schema* additionalItemsSchema_; - Schema* itemsList_; - Schema** itemsTuple_; + SchemaType* additionalItemsSchema_; + SchemaType* itemsList_; + SchemaType** itemsTuple_; SizeType itemsTupleCount_; SizeType minItems_; SizeType maxItems_; @@ -836,35 +866,43 @@ public: template friend class GenericSchemaValidator; + typedef Schema SchemaType; + template GenericSchemaDocument(const DocumentType& document) : root_() { - root_ = new Schema(static_cast(document)); + typedef typename DocumentType::ValueType ValueType; + root_ = CreateSchema(GenericPointer("#"), static_cast(document)); } ~GenericSchemaDocument() { delete root_; } + template + SchemaType* CreateSchema(const GenericPointer& p, const ValueType& v) { + return new SchemaType(this, p, v); + } + private: - Schema* root_; + SchemaType* root_; }; typedef GenericSchemaDocument > SchemaDocument; -template , typename Allocator = CrtAllocator > -class GenericSchemaValidator { +template , typename StateAllocator = CrtAllocator > +class GenericSchemaValidator : public ISchemaValidatorFactory, public ISchemaValidator { public: - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericSchemaDocument SchemaDocumentType; - friend class Schema; + typedef typename SchemaType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef GenericSchemaDocument SchemaDocumentType; GenericSchemaValidator( - const SchemaDocumentType& schema, - Allocator* allocator = 0, + const SchemaDocumentType& schemaDocument, + StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity/*, size_t documentStackCapacity = kDefaultDocumentStackCapacity*/) : - root_(*schema.root_), + root_(*schemaDocument.root_), outputHandler_(nullOutputHandler_), schemaStack_(allocator, schemaStackCapacity), // documentStack_(allocator, documentStackCapacity), @@ -873,13 +911,13 @@ public: } GenericSchemaValidator( - const SchemaDocumentType& schema, + const SchemaDocumentType& schemaDocument, OutputHandler& outputHandler, - Allocator* allocator = 0, + StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity/*, size_t documentStackCapacity = kDefaultDocumentStackCapacity*/) : - root_(*schema.root_), + root_(*schemaDocument.root_), outputHandler_(outputHandler), schemaStack_(allocator, schemaStackCapacity), // documentStack_(allocator, documentStackCapacity), @@ -898,7 +936,8 @@ public: valid_ = true; }; - bool IsValid() { return valid_; } + // Implementation of ISchemaValidator + virtual bool IsValid() const { return valid_; } #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ if (!valid_) return false; \ @@ -908,23 +947,23 @@ public: for (Context* context = schemaStack_.template Bottom(); context <= schemaStack_.template Top(); context++) {\ if (context->allOfValidators.validators)\ for (SizeType i_ = 0; i_ < context->allOfValidators.count; i_++)\ - context->allOfValidators.validators[i_]->method arg2;\ + static_cast(context->allOfValidators.validators[i_])->method arg2;\ if (context->anyOfValidators.validators)\ for (SizeType i_ = 0; i_ < context->anyOfValidators.count; i_++)\ - context->anyOfValidators.validators[i_]->method arg2;\ + static_cast(context->anyOfValidators.validators[i_])->method arg2;\ if (context->oneOfValidators.validators)\ for (SizeType i_ = 0; i_ < context->oneOfValidators.count; i_++)\ - context->oneOfValidators.validators[i_]->method arg2;\ + static_cast(context->oneOfValidators.validators[i_])->method arg2;\ if (context->notValidator)\ - context->notValidator->method arg2;\ + static_cast(context->notValidator)->method arg2;\ if (context->dependencyValidators.validators)\ for (SizeType i_ = 0; i_ < context->dependencyValidators.count; i_++)\ if (context->dependencyValidators.validators[i_])\ - context->dependencyValidators.validators[i_]->method arg2;\ + static_cast(context->dependencyValidators.validators[i_])->method arg2;\ if (context->patternPropertiesValidators.validators)\ for (SizeType i_ = 0; i_ < context->patternPropertiesValidators.count; i_++)\ if (context->patternPropertiesValidators.validators[i_])\ - context->patternPropertiesValidators.validators[i_]->method arg2; \ + static_cast(context->patternPropertiesValidators.validators[i_])->method arg2; \ } #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ @@ -982,18 +1021,17 @@ public: #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ - // Implementation of ISchemaValidatorFactory - GenericSchemaValidator* CreateSchemaValidator(const Schema& root) { + // Implementation of ISchemaValidatorFactory + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) const { return new GenericSchemaValidator(root); } private: - typedef Schema BaseSchemaType; - typedef typename BaseSchemaType::Context Context; + typedef typename SchemaType::Context Context; GenericSchemaValidator( - const BaseSchemaType& root, - Allocator* allocator = 0, + const SchemaType& root, + StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity/*, size_t documentStackCapacity = kDefaultDocumentStackCapacity*/) : @@ -1013,7 +1051,7 @@ private: return false; SizeType count = CurrentContext().patternPropertiesSchemaCount; - const BaseSchemaType** sa = CurrentContext().patternPropertiesSchemas; + const SchemaType** sa = CurrentContext().patternPropertiesSchemas; PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; if (CurrentContext().valueSchema) @@ -1021,8 +1059,8 @@ private: if (count > 0) { CurrentContext().objectPatternValidatorType = patternValidatorType; - SchemaValidatorArray& va = CurrentContext().patternPropertiesValidators; - va.validators = new GenericSchemaValidator*[count]; + SchemaValidatorArray& va = CurrentContext().patternPropertiesValidators; + va.validators = new ISchemaValidator*[count]; for (SizeType i = 0; i < count; i++) va.validators[va.count++] = CreateSchemaValidator(*sa[i]); } @@ -1038,22 +1076,22 @@ private: return true; } - void PushSchema(const BaseSchemaType& schema) { *schemaStack_.template Push() = Context(&schema); } + void PushSchema(const SchemaType& schema) { *schemaStack_.template Push() = Context(this, &schema); } void PopSchema() { schemaStack_.template Pop(1)->~Context(); } - const BaseSchemaType& CurrentSchema() { return *schemaStack_.template Top()->schema; } + const SchemaType& CurrentSchema() { return *schemaStack_.template Top()->schema; } Context& CurrentContext() { return *schemaStack_.template Top(); } static const size_t kDefaultSchemaStackCapacity = 1024; //static const size_t kDefaultDocumentStackCapacity = 256; - const BaseSchemaType& root_; - BaseReaderHandler nullOutputHandler_; + const SchemaType& root_; + BaseReaderHandler nullOutputHandler_; OutputHandler& outputHandler_; - internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) + internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) //internal::Stack documentStack_; //!< stack to store the current path of validating document (Value *) bool valid_; }; -typedef GenericSchemaValidator > SchemaValidator; +typedef GenericSchemaValidator SchemaValidator; RAPIDJSON_NAMESPACE_END diff --git a/test/unittest/pointertest.cpp b/test/unittest/pointertest.cpp index 72bfdbf..3346f24 100644 --- a/test/unittest/pointertest.cpp +++ b/test/unittest/pointertest.cpp @@ -32,6 +32,12 @@ static const char kJson[] = "{\n" " \"m~n\" : 8\n" "}"; +TEST(Pointer, DefaultConstructor) { + Pointer p; + EXPECT_TRUE(p.IsValid()); + EXPECT_EQ(0u, p.GetTokenCount()); +} + TEST(Pointer, Parse) { { Pointer p("");