diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index e22cb8d..55d91bf 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -131,6 +131,7 @@ public: virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; virtual void* CreateHasher() = 0; + virtual uint64_t GetHashCode(void* hasher) = 0; virtual void DestroryHasher(void* hasher) = 0; virtual void* MallocState(size_t size) = 0; virtual void* ReallocState(void* originalPtr, size_t originalSize, size_t newSize) = 0; @@ -146,7 +147,7 @@ class Hasher { public: typedef typename Encoding::Ch Ch; - Hasher(Allocator* allocator = 0) : stack_(allocator, kDefaultSize) {} + Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} bool Null() { return WriteType(kNullType); } bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } @@ -318,7 +319,6 @@ public: typedef typename EncodingType::Ch Ch; typedef SchemaValidationContext Context; typedef Schema SchemaType; - typedef Hasher HasherType; typedef GenericValue SValue; friend class GenericSchemaDocument; @@ -374,7 +374,10 @@ public: if (v->IsArray() && v->Size() > 0) { enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { - HasherType h; + typedef Hasher > EnumHasherType; + char buffer[256 + 24]; + MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); + EnumHasherType h(&hasherAllocator, 256); itr->Accept(h); enum_[enumCount_++] = h.GetHashCode(); } @@ -385,7 +388,7 @@ public: AssignIfExist(oneOf_, document, p, value, GetOneOfString()); if (const ValueType* v = GetMember(value, GetNotString())) { - document->CreateSchema(¬_, p.Append(GetNotString()), *v); + document->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v); notValidatorIndex_ = validatorCount_; validatorCount_++; } @@ -429,23 +432,23 @@ public: } if (properties && properties->IsObject()) { - PointerType q = p.Append(GetPropertiesString()); + PointerType q = p.Append(GetPropertiesString(), allocator_); for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { SizeType index; if (FindPropertyIndex(itr->name, &index)) - document->CreateSchema(&properties_[index].schema, q.Append(itr->name), itr->value); + document->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value); } } if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { - PointerType q = p.Append(GetPatternPropertiesString()); + PointerType q = p.Append(GetPatternPropertiesString(), allocator_); patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); patternPropertyCount_ = 0; for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { new (&patternProperties_[patternPropertyCount_]) PatternProperty(); patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); - document->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name), itr->value); + document->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value); patternPropertyCount_++; } } @@ -461,7 +464,7 @@ public: } if (dependencies && dependencies->IsObject()) { - PointerType q = p.Append(GetDependenciesString()); + PointerType q = p.Append(GetDependenciesString(), allocator_); hasDependencies_ = true; for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { SizeType sourceIndex; @@ -477,7 +480,7 @@ public: } else if (itr->value.IsObject()) { hasSchemaDependencies_ = true; - document->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name), itr->value); + document->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value); properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; validatorCount_++; } @@ -489,7 +492,7 @@ public: if (v->IsBool()) additionalProperties_ = v->GetBool(); else if (v->IsObject()) - document->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString()), *v); + document->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v); } AssignIfExist(minProperties_, value, GetMinPropertiesString()); @@ -497,14 +500,14 @@ public: // Array if (const ValueType* v = GetMember(value, GetItemsString())) { - PointerType q = p.Append(GetItemsString()); + PointerType q = p.Append(GetItemsString(), allocator_); if (v->IsObject()) // List validation document->CreateSchema(&itemsList_, q, *v); else if (v->IsArray()) { // Tuple validation itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); SizeType index = 0; for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) - document->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index), *itr); + document->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr); } } @@ -515,7 +518,7 @@ public: if (v->IsBool()) additionalItems_ = v->GetBool(); else if (v->IsObject()) - document->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString()), *v); + document->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v); } AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); @@ -617,7 +620,7 @@ public: } if (enum_) { - const uint64_t h = static_cast(context.hasher)->GetHashCode(); + const uint64_t h = context.factory.GetHashCode(context.hasher); for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; @@ -954,12 +957,12 @@ private: void AssignIfExist(SchemaArray& out, const DocumentType& document, const PointerType& p, const ValueType& value, const ValueType& name) { if (const ValueType* v = GetMember(value, name)) { if (v->IsArray() && v->Size() > 0) { - PointerType q = p.Append(name); + PointerType q = p.Append(name, allocator_); out.count = v->Size(); out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); memset(out.schemas, 0, sizeof(Schema*)* out.count); for (SizeType i = 0; i < out.count; i++) - document->CreateSchema(&out.schemas[i], q.Append(i), (*v)[i]); + document->CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i]); out.begin = validatorCount_; validatorCount_ += out.count; } @@ -1227,7 +1230,7 @@ public: typedef typename ValueType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; typedef internal::Schema SchemaType; - typedef GenericPointer PointerType; + typedef GenericPointer PointerType; friend class internal::Schema; template friend class GenericSchemaValidator; @@ -1257,7 +1260,7 @@ public: // Create entry in map if not exist if (!GetSchema(refEntry->source)) { - new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false); + new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); } } refEntry->~SchemaRefEntry(); @@ -1279,14 +1282,14 @@ public: private: struct SchemaRefEntry { - SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema) : source(s), target(t), schema(outSchema) {} + SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} PointerType source; PointerType target; const SchemaType** schema; }; struct SchemaEntry { - SchemaEntry(const PointerType& p, SchemaType* s, bool o) : pointer(p), schema(s), owned(o) {} + SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} ~SchemaEntry() { if (owned) { schema->~SchemaType(); @@ -1310,11 +1313,11 @@ private: *schema = s; for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) - CreateSchemaRecursive(0, pointer.Append(itr->name), itr->value); + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value); } else if (v.GetType() == kArrayType) for (SizeType i = 0; i < v.Size(); i++) - CreateSchemaRecursive(0, pointer.Append(i), v[i]); + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i]); } void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v) { @@ -1322,7 +1325,7 @@ private: if (v.IsObject()) { if (!HandleRefSchema(pointer, schema, v)) { SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, allocator_); - new (schemaMap_.template Push()) SchemaEntry(pointer, s, true); + new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); if (schema) *schema = s; } @@ -1348,7 +1351,7 @@ private: if (i > 0) { // Remote reference, resolve immediately if (remoteProvider_) { if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { - PointerType pointer(&s[i], len - i); + PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const SchemaType* s = remoteDocument->GetSchema(pointer)) { if (schema) @@ -1360,13 +1363,13 @@ private: } } else if (s[i] == '#') { // Local reference, defer resolution - PointerType pointer(&s[i], len - i); + PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const ValueType* nv = pointer.Get(*document_)) if (HandleRefSchema(source, schema, *nv)) return true; - new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema); + new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); return true; } } @@ -1555,11 +1558,11 @@ RAPIDJSON_MULTILINEMACRO_END // Implementation of ISchemaStateFactory virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { - return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, #if RAPIDJSON_SCHEMA_VERBOSE - , depth_ + 1 + depth_ + 1, #endif - ); + &GetStateAllocator()); } virtual void DestroySchemaValidator(ISchemaValidator* validator) { @@ -1572,6 +1575,10 @@ RAPIDJSON_MULTILINEMACRO_END return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); } + virtual uint64_t GetHashCode(void* hasher) { + return static_cast(hasher)->GetHashCode(); + } + virtual void DestroryHasher(void* hasher) { HasherType* h = static_cast(hasher); h->~HasherType(); diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 2a224bf..6a95d0c 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -837,7 +837,8 @@ TEST(SchemaValidator, AllOf_Nested) { INVALIDATE(s, "123", "", "allOf", ""); } -static char* ReadFile(const char* filename) { +template +static char* ReadFile(const char* filename, Allocator& allocator) { const char *paths[] = { "%s", "bin/%s", @@ -860,7 +861,7 @@ static char* ReadFile(const char* filename) { fseek(fp, 0, SEEK_END); size_t length = (size_t)ftell(fp); fseek(fp, 0, SEEK_SET); - char* json = (char*)malloc(length + 1); + char* json = (char*)allocator.Malloc(length + 1); size_t readLength = fread(json, 1, length, fp); json[readLength] = '\0'; fclose(fp); @@ -868,7 +869,8 @@ static char* ReadFile(const char* filename) { } TEST(SchemaValidator, ValidateMetaSchema) { - char* json = ReadFile("draft-04/schema"); + CrtAllocator allocator; + char* json = ReadFile("draft-04/schema", allocator); Document d; d.Parse(json); ASSERT_FALSE(d.HasParseError()); @@ -884,7 +886,7 @@ TEST(SchemaValidator, ValidateMetaSchema) { printf("Invalid document: %s\n", sb.GetString()); ADD_FAILURE(); } - free(json); + CrtAllocator::Free(json); } TEST(SchemaValidator, ValidateMetaSchema_UTF16) { @@ -892,7 +894,8 @@ TEST(SchemaValidator, ValidateMetaSchema_UTF16) { typedef GenericSchemaDocument SD; typedef GenericSchemaValidator SV; - char* json = ReadFile("draft-04/schema"); + CrtAllocator allocator; + char* json = ReadFile("draft-04/schema", allocator); D d; StringStream ss(json); @@ -910,13 +913,16 @@ TEST(SchemaValidator, ValidateMetaSchema_UTF16) { wprintf(L"Invalid document: %ls\n", sb.GetString()); ADD_FAILURE(); } - free(json); + CrtAllocator::Free(json); } template class RemoteSchemaDocumentProvider : public IGenericRemoteSchemaDocumentProvider { public: - RemoteSchemaDocumentProvider() : documentAllocator_(), schemaAllocator_() { + RemoteSchemaDocumentProvider() : + documentAllocator_(documentBuffer_, sizeof(documentBuffer_)), + schemaAllocator_(schemaBuffer_, sizeof(schemaBuffer_)) + { const char* filenames[kCount] = { "jsonschema/remotes/integer.json", "jsonschema/remotes/subSchemas.json", @@ -927,16 +933,20 @@ public: for (size_t i = 0; i < kCount; i++) { sd_[i] = 0; - char* json = ReadFile(filenames[i]); + char jsonBuffer[8192]; + MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer)); + char* json = ReadFile(filenames[i], jsonAllocator); if (!json) { printf("json remote file %s not found", filenames[i]); ADD_FAILURE(); } else { - DocumentType d(&documentAllocator_); + char stackBuffer[4096]; + MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer)); + DocumentType d(&documentAllocator_, 1024, &stackAllocator); d.Parse(json); sd_[i] = new SchemaDocumentType(d, 0, &schemaAllocator_); - free(json); + MemoryPoolAllocator<>::Free(json); } }; } @@ -961,7 +971,7 @@ public: } private: - typedef GenericDocument > DocumentType; + typedef GenericDocument, MemoryPoolAllocator<> > DocumentType; RemoteSchemaDocumentProvider(const RemoteSchemaDocumentProvider&); RemoteSchemaDocumentProvider& operator=(const RemoteSchemaDocumentProvider&); @@ -970,6 +980,8 @@ private: SchemaDocumentType* sd_[kCount]; typename DocumentType::AllocatorType documentAllocator_; typename SchemaDocumentType::AllocatorType schemaAllocator_; + char documentBuffer_[16384]; + char schemaBuffer_[128 * 1024]; }; TEST(SchemaValidator, TestSuite) { @@ -1013,10 +1025,12 @@ TEST(SchemaValidator, TestSuite) { typedef GenericSchemaDocument > SchemaDocumentType; RemoteSchemaDocumentProvider provider; + char jsonBuffer[65536]; char documentBuffer[65536]; char documentStackBuffer[65536]; char schemaBuffer[65536]; char validatorBuffer[65536]; + MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer)); MemoryPoolAllocator<> documentAllocator(documentBuffer, sizeof(documentBuffer)); MemoryPoolAllocator<> documentStackAllocator(documentStackBuffer, sizeof(documentStackBuffer)); MemoryPoolAllocator<> schemaAllocator(schemaBuffer, sizeof(schemaBuffer)); @@ -1025,7 +1039,7 @@ TEST(SchemaValidator, TestSuite) { for (size_t i = 0; i < sizeof(filenames) / sizeof(filenames[0]); i++) { char filename[FILENAME_MAX]; sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]); - char* json = ReadFile(filename); + char* json = ReadFile(filename, jsonAllocator); if (!json) { printf("json test suite file %s not found", filename); ADD_FAILURE(); @@ -1066,7 +1080,8 @@ TEST(SchemaValidator, TestSuite) { } } documentAllocator.Clear(); - free(json); + MemoryPoolAllocator<>::Free(json); + jsonAllocator.Clear(); } printf("%d / %d passed (%2d%%)\n", passCount, testCount, passCount * 100 / testCount); // if (passCount != testCount)