Commit 85c8b657 authored by miloyip's avatar miloyip

Achieve zero heap allocation for SchemaValidator.TestSuite

parent e20645f0
......@@ -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<SchemaDocumentType> Context;
typedef Schema<SchemaDocumentType> SchemaType;
typedef Hasher<EncodingType, AllocatorType> HasherType;
typedef GenericValue<EncodingType, AllocatorType> SValue;
friend class GenericSchemaDocument<ValueType, AllocatorType>;
......@@ -374,7 +374,10 @@ public:
if (v->IsArray() && v->Size() > 0) {
enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
HasherType h;
typedef Hasher<EncodingType, MemoryPoolAllocator<> > 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(&not_, p.Append(GetNotString()), *v);
document->CreateSchema(&not_, 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<PatternProperty*>(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<const Schema**>(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<HasherType*>(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<const Schema**>(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<GenericSchemaDocument> SchemaType;
typedef GenericPointer<ValueType, CrtAllocator> PointerType;
typedef GenericPointer<ValueType, Allocator> PointerType;
friend class internal::Schema<GenericSchemaDocument>;
template <typename, typename, typename>
friend class GenericSchemaValidator;
......@@ -1257,7 +1260,7 @@ public:
// Create entry in map if not exist
if (!GetSchema(refEntry->source)) {
new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false);
new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(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>()) SchemaEntry(pointer, s, true);
new (schemaMap_.template Push<SchemaEntry>()) 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>()) SchemaRefEntry(source, pointer, schema);
new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
return true;
}
}
......@@ -1555,11 +1558,11 @@ RAPIDJSON_MULTILINEMACRO_END
// Implementation of ISchemaStateFactory<SchemaType>
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<HasherType*>(hasher)->GetHashCode();
}
virtual void DestroryHasher(void* hasher) {
HasherType* h = static_cast<HasherType*>(hasher);
h->~HasherType();
......
......@@ -837,7 +837,8 @@ TEST(SchemaValidator, AllOf_Nested) {
INVALIDATE(s, "123", "", "allOf", "");
}
static char* ReadFile(const char* filename) {
template <typename Allocator = CrtAllocator>
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<D::ValueType> SD;
typedef GenericSchemaValidator<SD> 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 <typename SchemaDocumentType = SchemaDocument>
class RemoteSchemaDocumentProvider : public IGenericRemoteSchemaDocumentProvider<SchemaDocumentType> {
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<typename SchemaDocumentType::EncodingType, MemoryPoolAllocator<> > DocumentType;
typedef GenericDocument<typename SchemaDocumentType::EncodingType, MemoryPoolAllocator<>, 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<Value, MemoryPoolAllocator<> > SchemaDocumentType;
RemoteSchemaDocumentProvider<SchemaDocumentType> 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)
......
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