From bdf6da641e3e045e4c877f32dfd0c8faf7a7a83e Mon Sep 17 00:00:00 2001
From: "miloyip@gmail.com"
 <miloyip@gmail.com@c5894555-1306-4e8d-425f-1f6f381ee07c>
Date: Sun, 27 Nov 2011 15:18:12 +0000
Subject: [PATCH] Refactor GenericReader::ParseString(). Extract logic
 independent of kParseInsituFlag to GenericReader::ParseStringToStream().
 Eliminated RAPIDJSON_PUT() macro and made the function more readable.

git-svn-id: https://rapidjson.googlecode.com/svn/trunk@38 c5894555-1306-4e8d-425f-1f6f381ee07c
---
 include/rapidjson/reader.h | 88 ++++++++++++++++++--------------------
 1 file changed, 41 insertions(+), 47 deletions(-)

diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h
index 742b09d..b5625d8 100644
--- a/include/rapidjson/reader.h
+++ b/include/rapidjson/reader.h
@@ -373,9 +373,29 @@ private:
 		SizeType length_;
 	};
 
-	// Parse string, handling the prefix and suffix double quotes and escaping.
+	// Parse string and generate String event. Different code paths for kParseInsituFlag.
 	template<unsigned parseFlags, typename Stream, typename Handler>
 	void ParseString(Stream& stream, Handler& handler) {
+		Stream s = stream;	// Local copy for optimization
+		if (parseFlags & kParseInsituFlag) {
+			Ch *head = s.PutBegin();
+			ParseStringToStream<parseFlags>(s, s);
+			size_t length = s.PutEnd(head) - 1;
+			RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+			handler.String(head, SizeType(length), false);
+		}
+		else {
+			StackStream stackStream(stack_);
+			ParseStringToStream<parseFlags>(s, stackStream);
+			handler.String(stack_.template Pop<Ch>(stackStream.length_), stackStream.length_ - 1, true);
+		}
+		stream = s;		// Restore stream
+	}
+
+	// Parse string to an output stream
+	// This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
+	template<unsigned parseFlags, typename InputStream, typename OutputStream>
+	RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& input, OutputStream& output) {
 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 		static const char escape[256] = {
 			Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', 
@@ -386,74 +406,48 @@ private:
 		};
 #undef Z16
 
-		Stream s = stream;	// Use a local copy for optimization
-		RAPIDJSON_ASSERT(s.Peek() == '\"');
-		s.Take();	// Skip '\"'
-
-		// With kParseInsituFlag
-		Ch *head;
-		if (parseFlags & kParseInsituFlag)
-			head = s.PutBegin();
-
-		// Without kParseInsituFlag
-		StackStream stackStream(stack_);
-
-#define RAPIDJSON_PUT(x) (parseFlags & kParseInsituFlag ? s.Put(x) : stackStream.Put(x))
+		RAPIDJSON_ASSERT(input.Peek() == '\"');
+		input.Take();	// Skip '\"'
 
 		for (;;) {
-			Ch c = s.Peek();
+			Ch c = input.Peek();
 			if (c == '\\') {	// Escape
-				s.Take();
-				Ch e = s.Take();
+				input.Take();
+				Ch e = input.Take();
 				if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e])
-					RAPIDJSON_PUT(escape[(unsigned char)e]);
+					output.Put(escape[(unsigned char)e]);
 				else if (e == 'u') {	// Unicode
-					unsigned codepoint = ParseHex4(s);
+					unsigned codepoint = ParseHex4(input);
 					if (codepoint >= 0xD800 && codepoint <= 0xDBFF) {
 						// Handle UTF-16 surrogate pair
-						if (s.Take() != '\\' || s.Take() != 'u')
-							RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2);
-						unsigned codepoint2 = ParseHex4(s);
+						if (input.Take() != '\\' || input.Take() != 'u')
+							RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", input.Tell() - 2);
+						unsigned codepoint2 = ParseHex4(input);
 						if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)
-							RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2);
+							RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", input.Tell() - 2);
 						codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
 					}
-
-					if (parseFlags & kParseInsituFlag)
-						Encoding::Encode(s, codepoint);
-					else
-						Encoding::Encode(stackStream, codepoint);
+					Encoding::Encode(output, codepoint);
 				}
 				else
-					RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1);
+					RAPIDJSON_PARSE_ERROR("Unknown escape character", input.Tell() - 1);
 			}
 			else if (c == '"') {	// Closing double quote
-				s.Take();
-				if (parseFlags & kParseInsituFlag) {
-					size_t length = s.PutEnd(head);
-					RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
-					RAPIDJSON_PUT('\0');	// null-terminate the string
-					handler.String(head, SizeType(length), false);
-				}
-				else {
-					RAPIDJSON_PUT('\0');
-					handler.String(stack_.template Pop<Ch>(stackStream.length_), stackStream.length_ - 1, true);
-				}
-				stream = s;	// restore stream
+				input.Take();
+				output.Put('\0');	// null-terminate the string
 				return;
 			}
 			else if (c == '\0')
-				RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1);
+				RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", input.Tell() - 1);
 			else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
-				RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1);
+				RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", input.Tell() - 1);
 			else if (parseFlags & kParseValidateEncodingFlag) {
-				if ((parseFlags & kParseInsituFlag) ? !Encoding::Validate(s, s) : !Encoding::Validate(s, stackStream))
-					RAPIDJSON_PARSE_ERROR("Invalid encoding", s.Tell());
+				if (!Encoding::Validate(input, output))
+					RAPIDJSON_PARSE_ERROR("Invalid encoding", input.Tell());
 			}
 			else
-				RAPIDJSON_PUT(s.Take());	// Normal character, just copy
+				output.Put(input.Take());	// Normal character, just copy
 		}
-#undef RAPIDJSON_PUT
 	}
 
 	template<unsigned parseFlags, typename Stream, typename Handler>
-- 
2.18.0