Refactor template parameters in schema

This commit is contained in:
miloyip 2015-05-09 15:58:01 +08:00
parent 4a0b59121e
commit ed7e9bc9f0

View File

@ -45,12 +45,12 @@ RAPIDJSON_NAMESPACE_BEGIN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Forward declarations // Forward declarations
template <typename Encoding, typename Allocator> template <typename ValueType, typename Allocator>
class GenericSchemaDocument; class GenericSchemaDocument;
namespace internal { namespace internal {
template <typename Encoding, typename Allocator> template <typename SchemaDocumentType>
class Schema; class Schema;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -75,9 +75,9 @@ public:
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// SchemaValidationContext // SchemaValidationContext
template <typename Encoding, typename Allocator> template <typename SchemaDocumentType>
struct SchemaValidationContext { struct SchemaValidationContext {
typedef Schema<Encoding, Allocator> SchemaType; typedef Schema<SchemaDocumentType> SchemaType;
typedef ISchemaValidatorFactory<SchemaType> SchemaValidatorFactoryType; typedef ISchemaValidatorFactory<SchemaType> SchemaValidatorFactoryType;
enum PatternValidatorType { enum PatternValidatorType {
@ -142,19 +142,18 @@ struct SchemaValidationContext {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Schema // Schema
template <typename Encoding, typename Allocator> template <typename SchemaDocumentType>
class Schema { class Schema {
public: public:
typedef Encoding EncodingType; typedef typename SchemaDocumentType::ValueType ValueType;
typedef typename Encoding::Ch Ch; typedef typename SchemaDocumentType::AllocatorType AllocatorType;
typedef SchemaValidationContext<Encoding, Allocator> Context; typedef typename SchemaDocumentType::PointerType PointerType;
typedef GenericSchemaDocument<Encoding, Allocator> SchemaDocumentType; typedef typename ValueType::EncodingType EncodingType;
typedef Schema<Encoding, Allocator> SchemaType; typedef typename EncodingType::Ch Ch;
typedef GenericValue<Encoding, Allocator> ValueType; typedef SchemaValidationContext<SchemaDocumentType> Context;
// typedef GenericPointer<ValueType> PointerType; typedef Schema<SchemaDocumentType> SchemaType;
friend class GenericSchemaDocument<Encoding, Allocator>; friend SchemaDocumentType;
template <typename ValueType, typename PointerType>
Schema(SchemaDocumentType* document, const PointerType& p, const ValueType& value) : Schema(SchemaDocumentType* document, const PointerType& p, const ValueType& value) :
not_(), not_(),
ref_(), ref_(),
@ -187,6 +186,7 @@ public:
exclusiveMinimum_(false), exclusiveMinimum_(false),
exclusiveMaximum_(false) exclusiveMaximum_(false)
{ {
typedef typename SchemaDocumentType::ValueType ValueType;
typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstValueIterator ConstValueIterator;
typedef typename ValueType::ConstMemberIterator ConstMemberIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
@ -223,7 +223,7 @@ public:
const ValueType* dependencies = GetMember(value, "dependencies"); const ValueType* dependencies = GetMember(value, "dependencies");
{ {
// Gather properties from properties/required/dependencies // Gather properties from properties/required/dependencies
typedef GenericValue<Encoding, MemoryPoolAllocator<> > SValue; typedef ValueType SValue;
SValue allProperties(kArrayType); SValue allProperties(kArrayType);
if (properties && properties->IsObject()) if (properties && properties->IsObject())
@ -465,14 +465,14 @@ public:
CreateParallelValidator(context); CreateParallelValidator(context);
return return
(type_ & (1 << kNullSchemaType)) && (type_ & (1 << kNullSchemaType)) &&
(!enum_.IsArray() || CheckEnum(GenericValue<Encoding>().Move())); (!enum_.IsArray() || CheckEnum(ValueType().Move()));
} }
bool Bool(Context& context, bool b) const { bool Bool(Context& context, bool b) const {
CreateParallelValidator(context); CreateParallelValidator(context);
return return
(type_ & (1 << kBooleanSchemaType)) && (type_ & (1 << kBooleanSchemaType)) &&
(!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(b).Move())); (!enum_.IsArray() || CheckEnum(ValueType(b).Move()));
} }
bool Int(Context& context, int i) const { bool Int(Context& context, int i) const {
@ -480,7 +480,7 @@ public:
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false; return false;
return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(i).Move())); return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(ValueType(i).Move()));
} }
bool Uint(Context& context, unsigned u) const { bool Uint(Context& context, unsigned u) const {
@ -488,7 +488,7 @@ public:
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false; return false;
return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(u).Move())); return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(ValueType(u).Move()));
} }
bool Int64(Context& context, int64_t i) const { bool Int64(Context& context, int64_t i) const {
@ -496,7 +496,7 @@ public:
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false; return false;
return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(i).Move())); return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(ValueType(i).Move()));
} }
bool Uint64(Context& context, uint64_t u) const { bool Uint64(Context& context, uint64_t u) const {
@ -504,7 +504,7 @@ public:
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false; return false;
return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(u).Move())); return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(ValueType(u).Move()));
} }
bool Double(Context& context, double d) const { bool Double(Context& context, double d) const {
@ -512,7 +512,7 @@ public:
if ((type_ & (1 << kNumberSchemaType)) == 0) if ((type_ & (1 << kNumberSchemaType)) == 0)
return false; return false;
return CheckDouble(d) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(d).Move())); return CheckDouble(d) && (!enum_.IsArray() || CheckEnum(ValueType(d).Move()));
} }
bool String(Context& context, const Ch* str, SizeType length, bool) const { bool String(Context& context, const Ch* str, SizeType length, bool) const {
@ -525,14 +525,14 @@ public:
// return false; // return false;
if (minLength_ != 0 || maxLength_ != SizeType(~0)) { if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
SizeType count; SizeType count;
if (internal::CountStringCodePoint<Encoding>(str, length, &count) && (count < minLength_ || count > maxLength_)) if (internal::CountStringCodePoint<EncodingType>(str, length, &count) && (count < minLength_ || count > maxLength_))
return false; return false;
} }
if (pattern_ && !IsPatternMatch(pattern_, str, length)) if (pattern_ && !IsPatternMatch(pattern_, str, length))
return false; return false;
return !enum_.IsArray() || CheckEnum(GenericValue<Encoding>(str, length).Move()); return !enum_.IsArray() || CheckEnum(ValueType(str, length).Move());
} }
bool StartObject(Context& context) const { bool StartObject(Context& context) const {
@ -659,7 +659,7 @@ private:
struct SchemaArray { struct SchemaArray {
SchemaArray() : schemas(), count() {} SchemaArray() : schemas(), count() {}
~SchemaArray() { delete[] schemas; } ~SchemaArray() { delete[] schemas; }
const Schema<Encoding, Allocator>** schemas; const SchemaType** schemas;
SizeType count; SizeType count;
}; };
@ -744,8 +744,8 @@ private:
else if (type == "number" ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); else if (type == "number" ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
} }
bool CheckEnum(const GenericValue<Encoding>& v) const { bool CheckEnum(const ValueType& v) const {
for (typename GenericValue<Encoding>::ConstValueIterator itr = enum_.Begin(); itr != enum_.End(); ++itr) for (typename ValueType::ConstValueIterator itr = enum_.Begin(); itr != enum_.End(); ++itr)
if (v == *itr) if (v == *itr)
return true; return true;
return false; return false;
@ -814,7 +814,7 @@ private:
struct Property { struct Property {
Property() : schema(), dependenciesSchema(), dependencies(), required(false), typeless(true) {} Property() : schema(), dependenciesSchema(), dependencies(), required(false), typeless(true) {}
~Property() { delete[] dependencies; } ~Property() { delete[] dependencies; }
GenericValue<Encoding> name; ValueType name;
const SchemaType* schema; const SchemaType* schema;
const SchemaType* dependenciesSchema; const SchemaType* dependenciesSchema;
bool* dependencies; bool* dependencies;
@ -829,8 +829,8 @@ private:
const RegexType* pattern; const RegexType* pattern;
}; };
Allocator allocator_; AllocatorType allocator_;
GenericValue<Encoding> enum_; ValueType enum_;
SchemaArray allOf_; SchemaArray allOf_;
SchemaArray anyOf_; SchemaArray anyOf_;
SchemaArray oneOf_; SchemaArray oneOf_;
@ -872,20 +872,42 @@ private:
} // namespace internal } // namespace internal
///////////////////////////////////////////////////////////////////////////////
// IGenericRemoteSchemaDocumentProvider
template <typename ValueType, typename Allocator = MemoryPoolAllocator<> >
class IGenericRemoteSchemaDocumentProvider {
public:
typedef GenericSchemaDocument<ValueType, Allocator> SchemaDocumentType;
typedef typename ValueType::Ch Ch;
virtual ~IGenericRemoteSchemaDocumentProvider() {}
virtual SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
};
typedef IGenericRemoteSchemaDocumentProvider<Value> IRemoteSchemaDocumentProvider;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericSchemaDocument // GenericSchemaDocument
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> > template <typename ValueT, typename Allocator = MemoryPoolAllocator<> >
class GenericSchemaDocument { class GenericSchemaDocument {
public: public:
typedef internal::Schema<Encoding, Allocator> SchemaType; typedef ValueT ValueType;
friend class internal::Schema<Encoding, Allocator>; typedef IGenericRemoteSchemaDocumentProvider<ValueType, Allocator> IRemoteSchemaDocumentProviderType;
typedef Allocator AllocatorType;
typedef typename ValueType::EncodingType EncodingType;
typedef typename EncodingType::Ch Ch;
typedef internal::Schema<GenericSchemaDocument> SchemaType;
typedef GenericPointer<ValueType> PointerType;
friend class internal::Schema<GenericSchemaDocument>;
template <typename DocumentType> GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
GenericSchemaDocument(const DocumentType& document, Allocator* allocator = 0) : root_(), schemas_(), schemaCount_(), schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { remoteProvider_(remoteProvider),
typedef typename DocumentType::ValueType ValueType; root_(),
typedef SchemaEntry<ValueType> SchemaEntryType; schemaMap_(allocator, kInitialSchemaMapSize),
typedef GenericPointer<ValueType> PointerType; schemaRef_(allocator, kInitialSchemaRefSize)
{
// Generate root schema, it will call CreateSchema() to create sub-schemas, // Generate root schema, it will call CreateSchema() to create sub-schemas,
// And call AddRefSchema() if there are $ref. // And call AddRefSchema() if there are $ref.
@ -893,13 +915,13 @@ public:
// Resolve $ref // Resolve $ref
while (!schemaRef_.Empty()) { while (!schemaRef_.Empty()) {
SchemaEntryType* refEntry = schemaRef_.template Pop<SchemaEntryType>(1); SchemaEntry* refEntry = schemaRef_.template Pop<SchemaEntry>(1);
PointerType p = refEntry->pointer; // Due to re-entrance, PointerType p = refEntry->pointer; // Due to re-entrance,
SchemaType* source = refEntry->schema; // backup the entry first, SchemaType* source = refEntry->schema; // backup the entry first,
refEntry->~SchemaEntryType(); // and then destruct it. refEntry->~SchemaEntry(); // and then destruct it.
bool resolved = false; bool resolved = false;
for (SchemaEntryType* target = schemaMap_.template Bottom<SchemaEntryType>(); target <= schemaMap_.template Top<SchemaEntryType>(); ++target) for (SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target <= schemaMap_.template Top<SchemaEntry>(); ++target)
if (p == target->pointer) { if (p == target->pointer) {
source->ref_ = target->schema; source->ref_ = target->schema;
resolved = true; resolved = true;
@ -911,73 +933,89 @@ public:
if (const ValueType* v = p.Get(document)) if (const ValueType* v = p.Get(document))
source->ref_ = CreateSchema(p, *v); // cause re-entrance (modifying schemaRef_) source->ref_ = CreateSchema(p, *v); // cause re-entrance (modifying schemaRef_)
} }
}
// Copy to schemas_ and destroy schemaMap_ entries.
schemas_ = new SchemaType*[schemaCount_];
size_t i = schemaCount_;
while (!schemaMap_.Empty()) {
SchemaEntryType* e = schemaMap_.template Pop<SchemaEntryType>(1);
schemas_[--i] = e->schema;
e->~SchemaEntryType();
} }
} }
~GenericSchemaDocument() { ~GenericSchemaDocument() {
for (size_t i = 0; i < schemaCount_; i++) while (!schemaMap_.Empty()) {
delete schemas_[i]; SchemaEntry* e = schemaMap_.template Pop<SchemaEntry>(1);
delete [] schemas_; delete e->schema;
e->~SchemaEntry();
}
} }
const SchemaType& GetRoot() const { return *root_; } const SchemaType& GetRoot() const { return *root_; }
private: private:
template <typename ValueType>
struct SchemaEntry { struct SchemaEntry {
SchemaEntry(const GenericPointer<ValueType>& p, SchemaType* s) : pointer(p), schema(s) {} SchemaEntry(const GenericPointer<ValueType>& p, SchemaType* s) : pointer(p), schema(s) {}
GenericPointer<ValueType> pointer; GenericPointer<ValueType> pointer;
SchemaType* schema; SchemaType* schema;
}; };
template <typename ValueType>
const SchemaType* CreateSchema(const GenericPointer<ValueType>& pointer, const ValueType& v) { const SchemaType* CreateSchema(const GenericPointer<ValueType>& pointer, const ValueType& v) {
RAPIDJSON_ASSERT(pointer.IsValid()); RAPIDJSON_ASSERT(pointer.IsValid());
SchemaType* schema = new SchemaType(this, pointer, v); SchemaType* schema = new SchemaType(this, pointer, v);
new (schemaMap_.template Push<SchemaEntry<ValueType> >()) SchemaEntry<ValueType>(pointer, schema); new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, schema);
schemaCount_++;
return schema; return schema;
} }
template <typename ValueType>
void AddRefSchema(SchemaType* schema, const ValueType& v) { void AddRefSchema(SchemaType* schema, const ValueType& v) {
if (v.IsString()) { if (v.IsString()) {
GenericPointer<ValueType> pointer(v.GetString(), v.GetStringLength()); SizeType len = v.GetStringLength();
if (pointer.IsValid()) if (len > 0) {
new (schemaRef_.template Push<SchemaEntry<ValueType> >()) SchemaEntry<ValueType>(pointer, schema); const Ch* s = v.GetString();
SizeType i = 0;
while (i < len && s[i] != '#') // Find the first #
i++;
if (s[i] == '#') {
if (i > 0) { // Remote reference, resolve immediately
if (remoteProvider_) {
GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i);
GenericPointer<ValueType> pointer(s, len - i);
schema->ref_ = remoteDocument->GetSchema(pointer);
}
}
else { // Local reference, defer resolution
GenericPointer<ValueType> pointer(v.GetString(), v.GetStringLength());
if (pointer.IsValid())
new (schemaRef_.template Push<SchemaEntry>()) SchemaEntry(pointer, schema);
}
}
}
} }
} }
const SchemaType* GetSchema(const GenericPointer<ValueType>& pointer) {
(void)pointer;
return 0;
}
static const size_t kInitialSchemaMapSize = 1024; static const size_t kInitialSchemaMapSize = 1024;
static const size_t kInitialSchemaRefSize = 1024; static const size_t kInitialSchemaRefSize = 1024;
IRemoteSchemaDocumentProviderType* remoteProvider_;
const SchemaType* root_; //!< Root schema. const SchemaType* root_; //!< Root schema.
SchemaType** schemas_; //!< ALl schemas are owned by SchemaDocument
size_t schemaCount_; //!< Number of schemas owned
internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
}; };
typedef GenericSchemaDocument<UTF8<> > SchemaDocument; typedef GenericSchemaDocument<Value> SchemaDocument;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// GenericSchemaValidator // GenericSchemaValidator
template <typename SchemaType, typename OutputHandler = BaseReaderHandler<typename SchemaType::EncodingType>, typename StateAllocator = CrtAllocator > template <typename SchemaDocumentType, typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>, typename StateAllocator = CrtAllocator >
class GenericSchemaValidator : public internal::ISchemaValidatorFactory<SchemaType>, public internal::ISchemaValidator { class GenericSchemaValidator :
public internal::ISchemaValidatorFactory<typename SchemaDocumentType::SchemaType>,
public internal::ISchemaValidator
{
public: public:
typedef typename SchemaDocumentType::SchemaType SchemaType;
typedef typename SchemaType::EncodingType EncodingType; typedef typename SchemaType::EncodingType EncodingType;
typedef typename EncodingType::Ch Ch; typedef typename EncodingType::Ch Ch;
typedef GenericSchemaDocument<EncodingType> SchemaDocumentType;
GenericSchemaValidator( GenericSchemaValidator(
const SchemaDocumentType& schemaDocument, const SchemaDocumentType& schemaDocument,
@ -1176,7 +1214,7 @@ private:
bool valid_; bool valid_;
}; };
typedef GenericSchemaValidator<SchemaDocument::SchemaType> SchemaValidator; typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END