From 57e1c875534eb2e2c183c62e4421ad1a0bf8bf73 Mon Sep 17 00:00:00 2001 From: Kosta Date: Thu, 4 Sep 2014 15:14:18 +0200 Subject: [PATCH] add `Key()` method to the `Handler` concept For more details see: https://github.com/miloyip/rapidjson/issues/132 This commit tries to minimize the required code changes and forwards the `Handler::Key()` calls to `Handler::String()` wherever possible in order to not break existing code; or at least not code deriving from `BaseReaderHandler` when implementing a custom `Handler`. --- include/rapidjson/document.h | 4 +++- include/rapidjson/reader.h | 40 ++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 13acb381..310fc710 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1386,7 +1386,7 @@ int z = a[0u].GetInt(); // This works too. if (!handler.StartObject()) return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - if (!handler.String(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) + if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) return false; if (!m->value.Accept(handler)) return false; @@ -1794,6 +1794,8 @@ private: bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } + bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } + bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 701255fa..f02dd161 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -152,6 +152,7 @@ concept Handler { bool Double(double d); bool String(const Ch* str, SizeType length, bool copy); bool StartObject(); + bool Key(const Ch* str, SizeType length, bool copy); bool EndObject(SizeType memberCount); bool StartArray(); bool EndArray(SizeType elementCount); @@ -181,6 +182,7 @@ struct BaseReaderHandler { bool Double(double) { return static_cast(*this).Default(); } bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } bool StartObject() { return static_cast(*this).Default(); } + bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } bool EndObject(SizeType) { return static_cast(*this).Default(); } bool StartArray() { return static_cast(*this).Default(); } bool EndArray(SizeType) { return static_cast(*this).Default(); } @@ -471,7 +473,7 @@ private: if (is.Peek() != '"') RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); - ParseString(is, handler); + ParseKey(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespace(is); @@ -576,7 +578,7 @@ private: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); } - // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + // Helper function to parse four hexidecimal digits in \uXXXX in ParseStringOrKey(). template unsigned ParseHex4(InputStream& is) { unsigned codepoint = 0; @@ -616,8 +618,8 @@ private: }; // Parse string and generate String event. Different code paths for kParseInsituFlag. - template - void ParseString(InputStream& is, Handler& handler) { + template + void ParseStringOrKey(InputStream& is, Handler& handler) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); @@ -627,18 +629,38 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + if (isKey) { + if (!handler.Key((typename TargetEncoding::Ch*)head, SizeType(length), false)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } else { + if (!handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } } else { StackStream stackStream(stack_); ParseStringToStream(s, stackStream); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (!handler.String(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + if (isKey) { + if (!handler.Key(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } else { + if (!handler.String(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } } } + template + void ParseKey(InputStream& is, Handler& handler) { + return ParseStringOrKey(is, handler); + } + + template + void ParseString(InputStream& is, Handler& handler) { + return ParseStringOrKey(is, handler); + } + // Parse string to an output is // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. template @@ -1194,7 +1216,7 @@ private: } case IterativeParsingMemberKeyState: - ParseString(is, handler); + ParseKey(is, handler); if (HasParseError()) return IterativeParsingErrorState; else