From 0dbcc1cf2ea62a40adf2f713bdb21685d85653ed Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Mon, 11 Aug 2014 22:26:45 +0800 Subject: [PATCH] Add license and change indents from tab to space. --- build/premake4.lua | 270 +-- example/capitalize/capitalize.cpp | 74 +- example/condense/condense.cpp | 28 +- example/messagereader/messagereader.cpp | 70 +- example/pretty/pretty.cpp | 28 +- example/prettyauto/prettyauto.cpp | 56 +- example/serialize/serialize.cpp | 162 +- example/simpledom/simpledom.cpp | 28 +- example/simplereader/simplereader.cpp | 32 +- example/simplewriter/simplewriter.cpp | 2 +- example/tutorial/tutorial.cpp | 230 +- include/rapidjson/allocators.h | 316 +-- include/rapidjson/document.h | 2724 ++++++++++++----------- include/rapidjson/encodedstream.h | 378 ++-- include/rapidjson/encodings.h | 856 +++---- include/rapidjson/error/en.h | 80 +- include/rapidjson/error/error.h | 134 +- include/rapidjson/filereadstream.h | 116 +- include/rapidjson/filestream.h | 78 +- include/rapidjson/filewritestream.h | 108 +- include/rapidjson/internal/dtoa.h | 651 +++--- include/rapidjson/internal/itoa.h | 45 +- include/rapidjson/internal/meta.h | 38 +- include/rapidjson/internal/pow10.h | 66 +- include/rapidjson/internal/stack.h | 142 +- include/rapidjson/internal/strfunc.h | 34 +- include/rapidjson/memorybuffer.h | 62 +- include/rapidjson/memorystream.h | 68 +- include/rapidjson/prettywriter.h | 288 +-- include/rapidjson/rapidjson.h | 224 +- include/rapidjson/reader.h | 2028 ++++++++--------- include/rapidjson/stringbuffer.h | 60 +- include/rapidjson/writer.h | 566 ++--- test/perftest/jsoncpptest.cpp | 76 +- test/perftest/misctest.cpp | 1470 ++++++------ test/perftest/perftest.cpp | 28 +- test/perftest/perftest.h | 112 +- test/perftest/platformtest.cpp | 182 +- test/perftest/rapidjsontest.cpp | 390 ++-- test/perftest/ultrajsontest.cpp | 92 +- test/perftest/yajltest.cpp | 272 +-- test/unittest/documenttest.cpp | 292 +-- test/unittest/encodedstreamtest.cpp | 480 ++-- test/unittest/encodingstest.cpp | 732 +++--- test/unittest/filestreamtest.cpp | 150 +- test/unittest/jsoncheckertest.cpp | 126 +- test/unittest/readertest.cpp | 1358 +++++------ test/unittest/unittest.cpp | 28 +- test/unittest/unittest.h | 58 +- test/unittest/valuetest.cpp | 1558 ++++++------- test/unittest/writertest.cpp | 330 +-- 51 files changed, 9279 insertions(+), 8497 deletions(-) diff --git a/build/premake4.lua b/build/premake4.lua index 822804c..ba07131 100644 --- a/build/premake4.lua +++ b/build/premake4.lua @@ -1,165 +1,165 @@ function setTargetObjDir(outDir) - for _, cfg in ipairs(configurations()) do - for _, plat in ipairs(platforms()) do - local action = _ACTION or "" - - local prj = project() - - --"_debug_win32_vs2008" - local suffix = "_" .. cfg .. "_" .. plat .. "_" .. action - - targetPath = outDir - - suffix = string.lower(suffix) + for _, cfg in ipairs(configurations()) do + for _, plat in ipairs(platforms()) do + local action = _ACTION or "" + + local prj = project() + + --"_debug_win32_vs2008" + local suffix = "_" .. cfg .. "_" .. plat .. "_" .. action + + targetPath = outDir + + suffix = string.lower(suffix) - local obj_path = "../intermediate/" .. cfg .. "/" .. action .. "/" .. prj.name - - obj_path = string.lower(obj_path) - - configuration {cfg, plat} - targetdir(targetPath) - objdir(obj_path) - targetsuffix(suffix) - end - end + local obj_path = "../intermediate/" .. cfg .. "/" .. action .. "/" .. prj.name + + obj_path = string.lower(obj_path) + + configuration {cfg, plat} + targetdir(targetPath) + objdir(obj_path) + targetsuffix(suffix) + end + end end function linkLib(libBaseName) - for _, cfg in ipairs(configurations()) do - for _, plat in ipairs(platforms()) do - local action = _ACTION or "" - - local prj = project() - - local cfgName = cfg - - --"_debug_win32_vs2008" - local suffix = "_" .. cfgName .. "_" .. plat .. "_" .. action - - libFullName = libBaseName .. string.lower(suffix) - - configuration {cfg, plat} - links(libFullName) - end - end + for _, cfg in ipairs(configurations()) do + for _, plat in ipairs(platforms()) do + local action = _ACTION or "" + + local prj = project() + + local cfgName = cfg + + --"_debug_win32_vs2008" + local suffix = "_" .. cfgName .. "_" .. plat .. "_" .. action + + libFullName = libBaseName .. string.lower(suffix) + + configuration {cfg, plat} + links(libFullName) + end + end end solution "test" - configurations { "debug", "release" } - platforms { "x32", "x64" } + configurations { "debug", "release" } + platforms { "x32", "x64" } - location ("./" .. (_ACTION or "")) - language "C++" - flags { "ExtraWarnings" } - - configuration "debug" - defines { "DEBUG" } - flags { "Symbols" } + location ("./" .. (_ACTION or "")) + language "C++" + flags { "ExtraWarnings" } + + configuration "debug" + defines { "DEBUG" } + flags { "Symbols" } - configuration "release" - defines { "NDEBUG" } - flags { "Optimize" } + configuration "release" + defines { "NDEBUG" } + flags { "Optimize" } - configuration "vs*" - defines { "_CRT_SECURE_NO_WARNINGS" } - - configuration "gmake" - buildoptions "-msse4.2 -Wall -Wextra" + configuration "vs*" + defines { "_CRT_SECURE_NO_WARNINGS" } + + configuration "gmake" + buildoptions "-msse4.2 -Wall -Wextra" - project "gtest" - kind "StaticLib" - - defines { "GTEST_HAS_PTHREAD=0" } + project "gtest" + kind "StaticLib" + + defines { "GTEST_HAS_PTHREAD=0" } - files { - "../thirdparty/gtest/src/gtest-all.cc", - "../thirdparty/gtest/src/**.h", - } + files { + "../thirdparty/gtest/src/gtest-all.cc", + "../thirdparty/gtest/src/**.h", + } - includedirs { - "../thirdparty/gtest/", - "../thirdparty/gtest/include", - } + includedirs { + "../thirdparty/gtest/", + "../thirdparty/gtest/include", + } - setTargetObjDir("../thirdparty/lib") + setTargetObjDir("../thirdparty/lib") - project "unittest" - kind "ConsoleApp" - - if _ACTION == "gmake" then - buildoptions "-Werror -Weffc++ -Wswitch-default" - end + project "unittest" + kind "ConsoleApp" + + if _ACTION == "gmake" then + buildoptions "-Werror -Weffc++ -Wswitch-default" + end - files { - "../include/**.h", - "../test/unittest/**.cpp", - "../test/unittest/**.h", - } - - includedirs { - "../include/", - "../thirdparty/gtest/include/", - } + files { + "../include/**.h", + "../test/unittest/**.cpp", + "../test/unittest/**.h", + } + + includedirs { + "../include/", + "../thirdparty/gtest/include/", + } - libdirs "../thirdparty/lib" + libdirs "../thirdparty/lib" - setTargetObjDir("../bin") + setTargetObjDir("../bin") - linkLib "gtest" - links "gtest" - - project "perftest" - kind "ConsoleApp" - - files { - "../include/**.h", - "../test/perftest/**.cpp", - "../test/perftest/**.c", - "../test/perftest/**.h", - } - - includedirs { - "../include/", - "../thirdparty/gtest/include/", - "../thirdparty/", - "../thirdparty/jsoncpp/include/", - "../thirdparty/libjson/", - "../thirdparty/yajl/include/", - } + linkLib "gtest" + links "gtest" + + project "perftest" + kind "ConsoleApp" + + files { + "../include/**.h", + "../test/perftest/**.cpp", + "../test/perftest/**.c", + "../test/perftest/**.h", + } + + includedirs { + "../include/", + "../thirdparty/gtest/include/", + "../thirdparty/", + "../thirdparty/jsoncpp/include/", + "../thirdparty/libjson/", + "../thirdparty/yajl/include/", + } - libdirs "../thirdparty/lib" + libdirs "../thirdparty/lib" - setTargetObjDir("../bin") + setTargetObjDir("../bin") - linkLib "gtest" - links "gtest" + linkLib "gtest" + links "gtest" solution "example" - configurations { "debug", "release" } - platforms { "x32", "x64" } - location ("./" .. (_ACTION or "")) - language "C++" - flags { "ExtraWarnings" } - includedirs "../include/" + configurations { "debug", "release" } + platforms { "x32", "x64" } + location ("./" .. (_ACTION or "")) + language "C++" + flags { "ExtraWarnings" } + includedirs "../include/" - configuration "debug" - defines { "DEBUG" } - flags { "Symbols" } + configuration "debug" + defines { "DEBUG" } + flags { "Symbols" } - configuration "release" - defines { "NDEBUG" } - flags { "Optimize", "EnableSSE2" } + configuration "release" + defines { "NDEBUG" } + flags { "Optimize", "EnableSSE2" } - configuration "vs*" - defines { "_CRT_SECURE_NO_WARNINGS" } + configuration "vs*" + defines { "_CRT_SECURE_NO_WARNINGS" } - configuration "gmake" - buildoptions "-Werror -Wall -Wextra -Weffc++ -Wswitch-default" + configuration "gmake" + buildoptions "-Werror -Wall -Wextra -Weffc++ -Wswitch-default" - local examplepaths = os.matchdirs("../example/*") - for _, examplepath in ipairs(examplepaths) do - project(path.getname(examplepath)) - kind "ConsoleApp" - files(examplepath .. "/*") - setTargetObjDir("../bin") - end + local examplepaths = os.matchdirs("../example/*") + for _, examplepath in ipairs(examplepaths) do + project(path.getname(examplepath)) + kind "ConsoleApp" + files(examplepath .. "/*") + setTargetObjDir("../bin") + end diff --git a/example/capitalize/capitalize.cpp b/example/capitalize/capitalize.cpp index 69b07d8..b8d6086 100644 --- a/example/capitalize/capitalize.cpp +++ b/example/capitalize/capitalize.cpp @@ -15,51 +15,51 @@ using namespace rapidjson; template struct CapitalizeFilter { - CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {} + CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {} - bool Null() { return out_.Null(); } - bool Bool(bool b) { return out_.Bool(b); } - bool Int(int i) { return out_.Int(i); } - bool Uint(unsigned u) { return out_.Uint(u); } - bool Int64(int64_t i) { return out_.Int64(i); } - bool Uint64(uint64_t u) { return out_.Uint64(u); } - bool Double(double d) { return out_.Double(d); } - bool String(const char* str, SizeType length, bool) { - buffer_.clear(); - for (SizeType i = 0; i < length; i++) - buffer_.push_back(std::toupper(str[i])); - return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string - } - bool StartObject() { return out_.StartObject(); } - bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); } - bool StartArray() { return out_.StartArray(); } - bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); } + bool Null() { return out_.Null(); } + bool Bool(bool b) { return out_.Bool(b); } + bool Int(int i) { return out_.Int(i); } + bool Uint(unsigned u) { return out_.Uint(u); } + bool Int64(int64_t i) { return out_.Int64(i); } + bool Uint64(uint64_t u) { return out_.Uint64(u); } + bool Double(double d) { return out_.Double(d); } + bool String(const char* str, SizeType length, bool) { + buffer_.clear(); + for (SizeType i = 0; i < length; i++) + buffer_.push_back(std::toupper(str[i])); + return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string + } + bool StartObject() { return out_.StartObject(); } + bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); } + bool StartArray() { return out_.StartArray(); } + bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); } - OutputHandler& out_; - std::vector buffer_; + OutputHandler& out_; + std::vector buffer_; private: - CapitalizeFilter(const CapitalizeFilter&); - CapitalizeFilter& operator=(const CapitalizeFilter&); + CapitalizeFilter(const CapitalizeFilter&); + CapitalizeFilter& operator=(const CapitalizeFilter&); }; int main(int, char*[]) { - // Prepare JSON reader and input stream. - Reader reader; - char readBuffer[65536]; - FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); + // Prepare JSON reader and input stream. + Reader reader; + char readBuffer[65536]; + FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); - // Prepare JSON writer and output stream. - char writeBuffer[65536]; - FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); - Writer writer(os); + // Prepare JSON writer and output stream. + char writeBuffer[65536]; + FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); + Writer writer(os); - // JSON reader parse from the input stream and let writer generate the output. - CapitalizeFilter > filter(writer); - if (!reader.Parse(is, filter)) { - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); - return 1; - } + // JSON reader parse from the input stream and let writer generate the output. + CapitalizeFilter > filter(writer); + if (!reader.Parse(is, filter)) { + fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + return 1; + } - return 0; + return 0; } diff --git a/example/condense/condense.cpp b/example/condense/condense.cpp index bad3c91..05e2007 100644 --- a/example/condense/condense.cpp +++ b/example/condense/condense.cpp @@ -12,21 +12,21 @@ using namespace rapidjson; int main(int, char*[]) { - // Prepare JSON reader and input stream. - Reader reader; - char readBuffer[65536]; - FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); + // Prepare JSON reader and input stream. + Reader reader; + char readBuffer[65536]; + FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); - // Prepare JSON writer and output stream. - char writeBuffer[65536]; - FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); - Writer writer(os); + // Prepare JSON writer and output stream. + char writeBuffer[65536]; + FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); + Writer writer(os); - // JSON reader parse from the input stream and let writer generate the output. - if (!reader.Parse(is, writer)) { - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); - return 1; - } + // JSON reader parse from the input stream and let writer generate the output. + if (!reader.Parse(is, writer)) { + fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + return 1; + } - return 0; + return 0; } diff --git a/example/messagereader/messagereader.cpp b/example/messagereader/messagereader.cpp index f5317c2..cf6f1e1 100644 --- a/example/messagereader/messagereader.cpp +++ b/example/messagereader/messagereader.cpp @@ -18,38 +18,38 @@ RAPIDJSON_DIAG_OFF(effc++) #endif struct MessageHandler : public BaseReaderHandler<> { - MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {} + MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {} bool StartObject() { - switch (state_) { - case kExpectObjectStart: - state_ = kExpectNameOrObjectEnd; - return true; - default: - return false; - } + switch (state_) { + case kExpectObjectStart: + state_ = kExpectNameOrObjectEnd; + return true; + default: + return false; + } } bool String(const char* str, SizeType length, bool) { - switch (state_) { - case kExpectNameOrObjectEnd: + switch (state_) { + case kExpectNameOrObjectEnd: name_ = string(str, length); - state_ = kExpectValue; - return true; - case kExpectValue: - messages_.insert(MessageMap::value_type(name_, string(str, length))); - state_ = kExpectNameOrObjectEnd; - return true; - default: - return false; - } + state_ = kExpectValue; + return true; + case kExpectValue: + messages_.insert(MessageMap::value_type(name_, string(str, length))); + state_ = kExpectNameOrObjectEnd; + return true; + default: + return false; + } } bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; } - bool Default() { return false; } // All other events are invalid. + bool Default() { return false; } // All other events are invalid. - MessageMap messages_; + MessageMap messages_; enum State { kExpectObjectStart, kExpectNameOrObjectEnd, @@ -66,30 +66,30 @@ void ParseMessages(const char* json, MessageMap& messages) { Reader reader; MessageHandler handler; StringStream ss(json); - if (reader.Parse(ss, handler)) - messages.swap(handler.messages_); // Only change it if success. - else { - ParseErrorCode e = reader.GetParseErrorCode(); - size_t o = reader.GetErrorOffset(); - cout << "Error: " << GetParseError_En(e) << endl;; - cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl; - } + if (reader.Parse(ss, handler)) + messages.swap(handler.messages_); // Only change it if success. + else { + ParseErrorCode e = reader.GetParseErrorCode(); + size_t o = reader.GetErrorOffset(); + cout << "Error: " << GetParseError_En(e) << endl;; + cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl; + } } int main() { MessageMap messages; - const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }"; - cout << json1 << endl; + const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }"; + cout << json1 << endl; ParseMessages(json1, messages); for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr) cout << itr->first << ": " << itr->second << endl; - cout << endl << "Parse a JSON with invalid schema." << endl; - const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }"; - cout << json2 << endl; - ParseMessages(json2, messages); + cout << endl << "Parse a JSON with invalid schema." << endl; + const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }"; + cout << json2 << endl; + ParseMessages(json2, messages); return 0; } diff --git a/example/pretty/pretty.cpp b/example/pretty/pretty.cpp index cfb3f0f..164e388 100644 --- a/example/pretty/pretty.cpp +++ b/example/pretty/pretty.cpp @@ -10,21 +10,21 @@ using namespace rapidjson; int main(int, char*[]) { - // Prepare reader and input stream. - Reader reader; - char readBuffer[65536]; - FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); + // Prepare reader and input stream. + Reader reader; + char readBuffer[65536]; + FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); - // Prepare writer and output stream. - char writeBuffer[65536]; - FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); - PrettyWriter writer(os); + // Prepare writer and output stream. + char writeBuffer[65536]; + FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); + PrettyWriter writer(os); - // JSON reader parse from the input stream and let writer generate the output. - if (!reader.Parse(is, writer)) { - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); - return 1; - } + // JSON reader parse from the input stream and let writer generate the output. + if (!reader.Parse(is, writer)) { + fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + return 1; + } - return 0; + return 0; } diff --git a/example/prettyauto/prettyauto.cpp b/example/prettyauto/prettyauto.cpp index 3f85f40..0d30968 100644 --- a/example/prettyauto/prettyauto.cpp +++ b/example/prettyauto/prettyauto.cpp @@ -6,7 +6,7 @@ #include "rapidjson/prettywriter.h" #include "rapidjson/filereadstream.h" #include "rapidjson/filewritestream.h" -#include "rapidjson/encodedstream.h" // NEW +#include "rapidjson/encodedstream.h" // NEW #include "rapidjson/error/en.h" #ifdef _WIN32 #include @@ -17,40 +17,40 @@ using namespace rapidjson; int main(int, char*[]) { #ifdef _WIN32 - // Prevent Windows converting between CR+LF and LF - _setmode(_fileno(stdin), _O_BINARY); // NEW - _setmode(_fileno(stdout), _O_BINARY); // NEW + // Prevent Windows converting between CR+LF and LF + _setmode(_fileno(stdin), _O_BINARY); // NEW + _setmode(_fileno(stdout), _O_BINARY); // NEW #endif - // Prepare reader and input stream. - //Reader reader; - GenericReader, UTF8<> > reader; // CHANGED - char readBuffer[65536]; - FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); - AutoUTFInputStream eis(is); // NEW + // Prepare reader and input stream. + //Reader reader; + GenericReader, UTF8<> > reader; // CHANGED + char readBuffer[65536]; + FileReadStream is(stdin, readBuffer, sizeof(readBuffer)); + AutoUTFInputStream eis(is); // NEW - // Prepare writer and output stream. - char writeBuffer[65536]; - FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); + // Prepare writer and output stream. + char writeBuffer[65536]; + FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer)); #if 1 - // Use the same Encoding of the input. Also use BOM according to input. - typedef AutoUTFOutputStream OutputStream; // NEW - OutputStream eos(os, eis.GetType(), eis.HasBOM()); // NEW - PrettyWriter, AutoUTF > writer(eos); // CHANGED + // Use the same Encoding of the input. Also use BOM according to input. + typedef AutoUTFOutputStream OutputStream; // NEW + OutputStream eos(os, eis.GetType(), eis.HasBOM()); // NEW + PrettyWriter, AutoUTF > writer(eos); // CHANGED #else - // You may also use static bound encoding type, such as output to UTF-16LE with BOM - typedef EncodedOutputStream,FileWriteStream> OutputStream; // NEW - OutputStream eos(os, true); // NEW - PrettyWriter, UTF16LE<> > writer(eos); // CHANGED + // You may also use static bound encoding type, such as output to UTF-16LE with BOM + typedef EncodedOutputStream,FileWriteStream> OutputStream; // NEW + OutputStream eos(os, true); // NEW + PrettyWriter, UTF16LE<> > writer(eos); // CHANGED #endif - // JSON reader parse from the input stream and let writer generate the output. - //if (!reader.Parse(is, writer)) { - if (!reader.Parse(eis, writer)) { // CHANGED - fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); - return 1; - } + // JSON reader parse from the input stream and let writer generate the output. + //if (!reader.Parse(is, writer)) { + if (!reader.Parse(eis, writer)) { // CHANGED + fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode())); + return 1; + } - return 0; + return 0; } diff --git a/example/serialize/serialize.cpp b/example/serialize/serialize.cpp index 6dfe2d4..68a54ef 100644 --- a/example/serialize/serialize.cpp +++ b/example/serialize/serialize.cpp @@ -1,8 +1,8 @@ // Serialize example // This example shows writing JSON string with writer directly. -#include "rapidjson/prettywriter.h" // for stringify JSON -#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output +#include "rapidjson/prettywriter.h" // for stringify JSON +#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output #include #include #include @@ -11,23 +11,23 @@ using namespace rapidjson; class Person { public: - Person(const std::string& name, unsigned age) : name_(name), age_(age) {} - virtual ~Person(); + Person(const std::string& name, unsigned age) : name_(name), age_(age) {} + virtual ~Person(); protected: - template - void Serialize(Writer& writer) const { - // This base class just write out name-value pairs, without wrapping within an object. - writer.String("name"); - writer.String(name_.c_str(), (SizeType)name_.length()); // Suppling length of string is faster. + template + void Serialize(Writer& writer) const { + // This base class just write out name-value pairs, without wrapping within an object. + writer.String("name"); + writer.String(name_.c_str(), (SizeType)name_.length()); // Suppling length of string is faster. - writer.String("age"); - writer.Uint(age_); - } + writer.String("age"); + writer.Uint(age_); + } private: - std::string name_; - unsigned age_; + std::string name_; + unsigned age_; }; Person::~Person() { @@ -35,115 +35,115 @@ Person::~Person() { class Education { public: - Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {} + Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {} - template - void Serialize(Writer& writer) const { - writer.StartObject(); - - writer.String("school"); - writer.String(school_.c_str(), (SizeType)school_.length()); + template + void Serialize(Writer& writer) const { + writer.StartObject(); + + writer.String("school"); + writer.String(school_.c_str(), (SizeType)school_.length()); - writer.String("GPA"); - writer.Double(GPA_); + writer.String("GPA"); + writer.Double(GPA_); - writer.EndObject(); - } + writer.EndObject(); + } private: - std::string school_; - double GPA_; + std::string school_; + double GPA_; }; class Dependent : public Person { public: - Dependent(const std::string& name, unsigned age, Education* education = 0) : Person(name, age), education_(education) {} - Dependent(const Dependent& rhs) : Person(rhs), education_(0) { education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); } - virtual ~Dependent(); + Dependent(const std::string& name, unsigned age, Education* education = 0) : Person(name, age), education_(education) {} + Dependent(const Dependent& rhs) : Person(rhs), education_(0) { education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); } + virtual ~Dependent(); - Dependent& operator=(const Dependent& rhs) { - if (this == &rhs) - return *this; + Dependent& operator=(const Dependent& rhs) { + if (this == &rhs) + return *this; delete education_; - education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); - return *this; - } + education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); + return *this; + } - template - void Serialize(Writer& writer) const { - writer.StartObject(); + template + void Serialize(Writer& writer) const { + writer.StartObject(); - Person::Serialize(writer); + Person::Serialize(writer); - writer.String("education"); - if (education_) - education_->Serialize(writer); - else - writer.Null(); + writer.String("education"); + if (education_) + education_->Serialize(writer); + else + writer.Null(); - writer.EndObject(); - } + writer.EndObject(); + } private: - Education *education_; + Education *education_; }; Dependent::~Dependent() { - delete education_; + delete education_; } class Employee : public Person { public: - Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {} - virtual ~Employee(); + Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {} + virtual ~Employee(); - void AddDependent(const Dependent& dependent) { - dependents_.push_back(dependent); - } + void AddDependent(const Dependent& dependent) { + dependents_.push_back(dependent); + } - template - void Serialize(Writer& writer) const { - writer.StartObject(); + template + void Serialize(Writer& writer) const { + writer.StartObject(); - Person::Serialize(writer); + Person::Serialize(writer); - writer.String("married"); - writer.Bool(married_); + writer.String("married"); + writer.Bool(married_); - writer.String(("dependents")); - writer.StartArray(); - for (std::vector::const_iterator dependentItr = dependents_.begin(); dependentItr != dependents_.end(); ++dependentItr) - dependentItr->Serialize(writer); - writer.EndArray(); + writer.String(("dependents")); + writer.StartArray(); + for (std::vector::const_iterator dependentItr = dependents_.begin(); dependentItr != dependents_.end(); ++dependentItr) + dependentItr->Serialize(writer); + writer.EndArray(); - writer.EndObject(); - } + writer.EndObject(); + } private: - std::vector dependents_; - bool married_; + std::vector dependents_; + bool married_; }; Employee::~Employee() { } int main(int, char*[]) { - std::vector employees; + std::vector employees; - employees.push_back(Employee("Milo YIP", 34, true)); - employees.back().AddDependent(Dependent("Lua YIP", 3, new Education("Happy Kindergarten", 3.5))); - employees.back().AddDependent(Dependent("Mio YIP", 1)); + employees.push_back(Employee("Milo YIP", 34, true)); + employees.back().AddDependent(Dependent("Lua YIP", 3, new Education("Happy Kindergarten", 3.5))); + employees.back().AddDependent(Dependent("Mio YIP", 1)); - employees.push_back(Employee("Percy TSE", 30, false)); + employees.push_back(Employee("Percy TSE", 30, false)); - FileStream s(stdout); - PrettyWriter writer(s); // Can also use Writer for condensed formatting + FileStream s(stdout); + PrettyWriter writer(s); // Can also use Writer for condensed formatting - writer.StartArray(); - for (std::vector::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr) - employeeItr->Serialize(writer); - writer.EndArray(); + writer.StartArray(); + for (std::vector::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr) + employeeItr->Serialize(writer); + writer.EndArray(); - return 0; + return 0; } diff --git a/example/simpledom/simpledom.cpp b/example/simpledom/simpledom.cpp index a2c9121..8038419 100644 --- a/example/simpledom/simpledom.cpp +++ b/example/simpledom/simpledom.cpp @@ -9,21 +9,21 @@ using namespace rapidjson; int main() { - // 1. Parse a JSON string into DOM. - const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; - Document d; - d.Parse(json); + // 1. Parse a JSON string into DOM. + const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; + Document d; + d.Parse(json); - // 2. Modify it by DOM. - Value& s = d["stars"]; - s.SetInt(s.GetInt() + 1); + // 2. Modify it by DOM. + Value& s = d["stars"]; + s.SetInt(s.GetInt() + 1); - // 3. Stringify the DOM - StringBuffer buffer; - Writer writer(buffer); - d.Accept(writer); + // 3. Stringify the DOM + StringBuffer buffer; + Writer writer(buffer); + d.Accept(writer); - // Output {"project":"rapidjson","stars":11} - std::cout << buffer.GetString() << std::endl; - return 0; + // Output {"project":"rapidjson","stars":11} + std::cout << buffer.GetString() << std::endl; + return 0; } diff --git a/example/simplereader/simplereader.cpp b/example/simplereader/simplereader.cpp index ed2bd3b..9914253 100644 --- a/example/simplereader/simplereader.cpp +++ b/example/simplereader/simplereader.cpp @@ -5,21 +5,21 @@ using namespace rapidjson; using namespace std; struct MyHandler { - bool Null() { cout << "Null()" << endl; return true; } - bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; } - bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; } - bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; } - bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; } - bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; } - bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; } + bool Null() { cout << "Null()" << endl; return true; } + bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; } + bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; } + bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; } + bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; } + bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; } + bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; } bool String(const char* str, SizeType length, bool copy) { - cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl; - return true; - } - bool StartObject() { cout << "StartObject()" << endl; return true; } - bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; } - bool StartArray() { cout << "StartArray()" << endl; return true; } - bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; } + cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl; + return true; + } + bool StartObject() { cout << "StartObject()" << endl; return true; } + bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; } + bool StartArray() { cout << "StartArray()" << endl; return true; } + bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; } }; int main() { @@ -28,7 +28,7 @@ int main() { MyHandler handler; Reader reader; StringStream ss(json); - reader.Parse(ss, handler); + reader.Parse(ss, handler); - return 0; + return 0; } diff --git a/example/simplewriter/simplewriter.cpp b/example/simplewriter/simplewriter.cpp index 98e5b2c..f889150 100644 --- a/example/simplewriter/simplewriter.cpp +++ b/example/simplewriter/simplewriter.cpp @@ -31,5 +31,5 @@ int main() { cout << s.GetString() << endl; - return 0; + return 0; } diff --git a/example/tutorial/tutorial.cpp b/example/tutorial/tutorial.cpp index c0aca10..fc96874 100644 --- a/example/tutorial/tutorial.cpp +++ b/example/tutorial/tutorial.cpp @@ -1,156 +1,156 @@ // Hello World example // This example shows basic usage of DOM-style API. -#include "rapidjson/document.h" // rapidjson's DOM-style API -#include "rapidjson/prettywriter.h" // for stringify JSON -#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output +#include "rapidjson/document.h" // rapidjson's DOM-style API +#include "rapidjson/prettywriter.h" // for stringify JSON +#include "rapidjson/filestream.h" // wrapper of C stream for prettywriter as output #include using namespace rapidjson; int main(int, char*[]) { - //////////////////////////////////////////////////////////////////////////// - // 1. Parse a JSON text string to a document. + //////////////////////////////////////////////////////////////////////////// + // 1. Parse a JSON text string to a document. - const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; - printf("Original JSON:\n %s\n", json); + const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "; + printf("Original JSON:\n %s\n", json); - Document document; // Default template parameter uses UTF8 and MemoryPoolAllocator. + Document document; // Default template parameter uses UTF8 and MemoryPoolAllocator. #if 0 - // "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream(). - if (document.Parse(json).HasParseError()) - return 1; + // "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream(). + if (document.Parse(json).HasParseError()) + return 1; #else - // In-situ parsing, decode strings directly in the source string. Source must be string. - { - char buffer[sizeof(json)]; - memcpy(buffer, json, sizeof(json)); - if (document.ParseInsitu(buffer).HasParseError()) - return 1; - } + // In-situ parsing, decode strings directly in the source string. Source must be string. + { + char buffer[sizeof(json)]; + memcpy(buffer, json, sizeof(json)); + if (document.ParseInsitu(buffer).HasParseError()) + return 1; + } #endif - printf("\nParsing to document succeeded.\n"); + printf("\nParsing to document succeeded.\n"); - //////////////////////////////////////////////////////////////////////////// - // 2. Access values in document. + //////////////////////////////////////////////////////////////////////////// + // 2. Access values in document. - printf("\nAccess values in document:\n"); - assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array. + printf("\nAccess values in document:\n"); + assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array. - assert(document.HasMember("hello")); - assert(document["hello"].IsString()); - printf("hello = %s\n", document["hello"].GetString()); + assert(document.HasMember("hello")); + assert(document["hello"].IsString()); + printf("hello = %s\n", document["hello"].GetString()); - // Since version 0.2, you can use single lookup to check the existing of member and its value: - Value::MemberIterator hello = document.FindMember("hello"); - assert(hello != document.MemberEnd()); - assert(hello->value.IsString()); - assert(strcmp("world", hello->value.GetString()) == 0); - (void)hello; + // Since version 0.2, you can use single lookup to check the existing of member and its value: + Value::MemberIterator hello = document.FindMember("hello"); + assert(hello != document.MemberEnd()); + assert(hello->value.IsString()); + assert(strcmp("world", hello->value.GetString()) == 0); + (void)hello; - assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue(). - printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); + assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue(). + printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); - assert(document["f"].IsBool()); - printf("f = %s\n", document["f"].GetBool() ? "true" : "false"); + assert(document["f"].IsBool()); + printf("f = %s\n", document["f"].GetBool() ? "true" : "false"); - printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); + printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); - assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type. - assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true. - printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"] + assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type. + assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true. + printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"] - assert(document["pi"].IsNumber()); - assert(document["pi"].IsDouble()); - printf("pi = %g\n", document["pi"].GetDouble()); + assert(document["pi"].IsNumber()); + assert(document["pi"].IsDouble()); + printf("pi = %g\n", document["pi"].GetDouble()); - { - const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster. - assert(a.IsArray()); - for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t. - printf("a[%d] = %d\n", i, a[i].GetInt()); - - // Note: - //int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type. - int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work. - int z = a[0u].GetInt(); // This works too. - (void)y; - (void)z; + { + const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster. + assert(a.IsArray()); + for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t. + printf("a[%d] = %d\n", i, a[i].GetInt()); + + // Note: + //int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type. + int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work. + int z = a[0u].GetInt(); // This works too. + (void)y; + (void)z; - // Iterating array with iterators - printf("a = "); - for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) - printf("%d ", itr->GetInt()); - printf("\n"); - } + // Iterating array with iterators + printf("a = "); + for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) + printf("%d ", itr->GetInt()); + printf("\n"); + } - // Iterating object members - static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" }; - for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr) - printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]); + // Iterating object members + static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" }; + for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr) + printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]); - //////////////////////////////////////////////////////////////////////////// - // 3. Modify values in document. + //////////////////////////////////////////////////////////////////////////// + // 3. Modify values in document. - // Change i to a bigger number - { - uint64_t f20 = 1; // compute factorial of 20 - for (uint64_t j = 1; j <= 20; j++) - f20 *= j; - document["i"] = f20; // Alternate form: document["i"].SetUint64(f20) - assert(!document["i"].IsInt()); // No longer can be cast as int or uint. - } + // Change i to a bigger number + { + uint64_t f20 = 1; // compute factorial of 20 + for (uint64_t j = 1; j <= 20; j++) + f20 *= j; + document["i"] = f20; // Alternate form: document["i"].SetUint64(f20) + assert(!document["i"].IsInt()); // No longer can be cast as int or uint. + } - // Adding values to array. - { - Value& a = document["a"]; // This time we uses non-const reference. - Document::AllocatorType& allocator = document.GetAllocator(); - for (int i = 5; i <= 10; i++) - a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's. + // Adding values to array. + { + Value& a = document["a"]; // This time we uses non-const reference. + Document::AllocatorType& allocator = document.GetAllocator(); + for (int i = 5; i <= 10; i++) + a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's. - // Fluent API - a.PushBack("Lua", allocator).PushBack("Mio", allocator); - } + // Fluent API + a.PushBack("Lua", allocator).PushBack("Mio", allocator); + } - // Making string values. + // Making string values. - // This version of SetString() just store the pointer to the string. - // So it is for literal and string that exists within value's life-cycle. - { - document["hello"] = "rapidjson"; // This will invoke strlen() - // Faster version: - // document["hello"].SetString("rapidjson", 9); - } + // This version of SetString() just store the pointer to the string. + // So it is for literal and string that exists within value's life-cycle. + { + document["hello"] = "rapidjson"; // This will invoke strlen() + // Faster version: + // document["hello"].SetString("rapidjson", 9); + } - // This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer. - Value author; - { - char buffer[10]; - int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string. + // This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer. + Value author; + { + char buffer[10]; + int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string. - author.SetString(buffer, static_cast(len), document.GetAllocator()); - // Shorter but slower version: - // document["hello"].SetString(buffer, document.GetAllocator()); + author.SetString(buffer, static_cast(len), document.GetAllocator()); + // Shorter but slower version: + // document["hello"].SetString(buffer, document.GetAllocator()); - // Constructor version: - // Value author(buffer, len, document.GetAllocator()); - // Value author(buffer, document.GetAllocator()); - memset(buffer, 0, sizeof(buffer)); // For demonstration purpose. - } - // Variable 'buffer' is unusable now but 'author' has already made a copy. - document.AddMember("author", author, document.GetAllocator()); + // Constructor version: + // Value author(buffer, len, document.GetAllocator()); + // Value author(buffer, document.GetAllocator()); + memset(buffer, 0, sizeof(buffer)); // For demonstration purpose. + } + // Variable 'buffer' is unusable now but 'author' has already made a copy. + document.AddMember("author", author, document.GetAllocator()); - assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null. + assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null. - //////////////////////////////////////////////////////////////////////////// - // 4. Stringify JSON + //////////////////////////////////////////////////////////////////////////// + // 4. Stringify JSON - printf("\nModified JSON with reformatting:\n"); - FileStream f(stdout); - PrettyWriter writer(f); - document.Accept(writer); // Accept() traverses the DOM and generates Handler events. + printf("\nModified JSON with reformatting:\n"); + FileStream f(stdout); + PrettyWriter writer(f); + document.Accept(writer); // Accept() traverses the DOM and generates Handler events. - return 0; + return 0; } diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h index b12c31b..6597a9d 100644 --- a/include/rapidjson/allocators.h +++ b/include/rapidjson/allocators.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_ALLOCATORS_H_ #define RAPIDJSON_ALLOCATORS_H_ @@ -9,31 +29,31 @@ namespace rapidjson { // Allocator /*! \class rapidjson::Allocator - \brief Concept for allocating, resizing and freeing memory block. - - Note that Malloc() and Realloc() are non-static but Free() is static. - - So if an allocator need to support Free(), it needs to put its pointer in - the header of memory block. + \brief Concept for allocating, resizing and freeing memory block. + + Note that Malloc() and Realloc() are non-static but Free() is static. + + So if an allocator need to support Free(), it needs to put its pointer in + the header of memory block. \code concept Allocator { - static const bool kNeedFree; //!< Whether this allocator needs to call Free(). + static const bool kNeedFree; //!< Whether this allocator needs to call Free(). - // Allocate a memory block. - // \param size of the memory block in bytes. - // \returns pointer to the memory block. - void* Malloc(size_t size); + // Allocate a memory block. + // \param size of the memory block in bytes. + // \returns pointer to the memory block. + void* Malloc(size_t size); - // Resize a memory block. - // \param originalPtr The pointer to current memory block. Null pointer is permitted. - // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) - // \param newSize the new size in bytes. - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); + // Resize a memory block. + // \param originalPtr The pointer to current memory block. Null pointer is permitted. + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) + // \param newSize the new size in bytes. + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); - // Free a memory block. - // \param pointer to the memory block. Null pointer is permitted. - static void Free(void *ptr); + // Free a memory block. + // \param pointer to the memory block. Null pointer is permitted. + static void Free(void *ptr); }; \endcode */ @@ -43,14 +63,14 @@ concept Allocator { //! C-runtime library allocator. /*! This class is just wrapper for standard C library memory routines. - \note implements Allocator concept + \note implements Allocator concept */ class CrtAllocator { public: - static const bool kNeedFree = true; - void* Malloc(size_t size) { return malloc(size); } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); } - static void Free(void *ptr) { free(ptr); } + static const bool kNeedFree = true; + void* Malloc(size_t size) { return malloc(size); } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); } + static void Free(void *ptr) { free(ptr); } }; /////////////////////////////////////////////////////////////////////////////// @@ -70,155 +90,155 @@ public: The user-buffer is not deallocated by this allocator. \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. - \note implements Allocator concept + \note implements Allocator concept */ template class MemoryPoolAllocator { public: - static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) - //! Constructor with chunkSize. - /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) - { - if (!baseAllocator_) - ownBaseAllocator_ = baseAllocator_ = new BaseAllocator(); - AddChunk(chunk_capacity_); - } + //! Constructor with chunkSize. + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + if (!baseAllocator_) + ownBaseAllocator_ = baseAllocator_ = new BaseAllocator(); + AddChunk(chunk_capacity_); + } - //! Constructor with user-supplied buffer. - /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. + //! Constructor with user-supplied buffer. + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. - The user buffer will not be deallocated when this allocator is destructed. + The user buffer will not be deallocated when this allocator is destructed. - \param buffer User supplied buffer. - \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). - \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. - \param baseAllocator The allocator for allocating memory chunks. - */ - MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : - chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) - { - RAPIDJSON_ASSERT(buffer != 0); - RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); - chunkHead_ = reinterpret_cast(buffer); - chunkHead_->capacity = size - sizeof(ChunkHeader); - chunkHead_->size = 0; - chunkHead_->next = 0; - } + \param buffer User supplied buffer. + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. + \param baseAllocator The allocator for allocating memory chunks. + */ + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) + { + RAPIDJSON_ASSERT(buffer != 0); + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); + chunkHead_ = reinterpret_cast(buffer); + chunkHead_->capacity = size - sizeof(ChunkHeader); + chunkHead_->size = 0; + chunkHead_->next = 0; + } - //! Destructor. - /*! This deallocates all memory chunks, excluding the user-supplied buffer. - */ - ~MemoryPoolAllocator() { - Clear(); - delete ownBaseAllocator_; - } + //! Destructor. + /*! This deallocates all memory chunks, excluding the user-supplied buffer. + */ + ~MemoryPoolAllocator() { + Clear(); + delete ownBaseAllocator_; + } - //! Deallocates all memory chunks, excluding the user-supplied buffer. - void Clear() { - while(chunkHead_ != 0 && chunkHead_ != userBuffer_) { - ChunkHeader* next = chunkHead_->next; - baseAllocator_->Free(chunkHead_); - chunkHead_ = next; - } - } + //! Deallocates all memory chunks, excluding the user-supplied buffer. + void Clear() { + while(chunkHead_ != 0 && chunkHead_ != userBuffer_) { + ChunkHeader* next = chunkHead_->next; + baseAllocator_->Free(chunkHead_); + chunkHead_ = next; + } + } - //! Computes the total capacity of allocated memory chunks. - /*! \return total capacity in bytes. - */ - size_t Capacity() const { - size_t capacity = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) - capacity += c->capacity; - return capacity; - } + //! Computes the total capacity of allocated memory chunks. + /*! \return total capacity in bytes. + */ + size_t Capacity() const { + size_t capacity = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + capacity += c->capacity; + return capacity; + } - //! Computes the memory blocks allocated. - /*! \return total used bytes. - */ - size_t Size() const { - size_t size = 0; - for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) - size += c->size; - return size; - } + //! Computes the memory blocks allocated. + /*! \return total used bytes. + */ + size_t Size() const { + size_t size = 0; + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) + size += c->size; + return size; + } - //! Allocates a memory block. (concept Allocator) - void* Malloc(size_t size) { - size = RAPIDJSON_ALIGN(size); - if (chunkHead_->size + size > chunkHead_->capacity) - AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); + //! Allocates a memory block. (concept Allocator) + void* Malloc(size_t size) { + size = RAPIDJSON_ALIGN(size); + if (chunkHead_->size + size > chunkHead_->capacity) + AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); - void *buffer = reinterpret_cast(chunkHead_ + 1) + chunkHead_->size; - chunkHead_->size += size; - return buffer; - } + void *buffer = reinterpret_cast(chunkHead_ + 1) + chunkHead_->size; + chunkHead_->size += size; + return buffer; + } - //! Resizes a memory block (concept Allocator) - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { - if (originalPtr == 0) - return Malloc(newSize); + //! Resizes a memory block (concept Allocator) + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { + if (originalPtr == 0) + return Malloc(newSize); - // Do not shrink if new size is smaller than original - if (originalSize >= newSize) - return originalPtr; + // Do not shrink if new size is smaller than original + if (originalSize >= newSize) + return originalPtr; - // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { - size_t increment = static_cast(newSize - originalSize); - increment = RAPIDJSON_ALIGN(increment); - if (chunkHead_->size + increment <= chunkHead_->capacity) { - chunkHead_->size += increment; - return originalPtr; - } - } + // Simply expand it if it is the last allocation and there is sufficient space + if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { + size_t increment = static_cast(newSize - originalSize); + increment = RAPIDJSON_ALIGN(increment); + if (chunkHead_->size + increment <= chunkHead_->capacity) { + chunkHead_->size += increment; + return originalPtr; + } + } - // Realloc process: allocate and copy memory, do not free original buffer. - void* newBuffer = Malloc(newSize); - RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. - return memcpy(newBuffer, originalPtr, originalSize); - } + // Realloc process: allocate and copy memory, do not free original buffer. + void* newBuffer = Malloc(newSize); + RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. + return memcpy(newBuffer, originalPtr, originalSize); + } - //! Frees a memory block (concept Allocator) - static void Free(void *ptr) { (void)ptr; } // Do nothing + //! Frees a memory block (concept Allocator) + static void Free(void *ptr) { (void)ptr; } // Do nothing private: - //! Copy constructor is not permitted. - MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; - //! Copy assignment operator is not permitted. - MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; + //! Copy constructor is not permitted. + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; + //! Copy assignment operator is not permitted. + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; - //! Creates a new chunk. - /*! \param capacity Capacity of the chunk in bytes. - */ - void AddChunk(size_t capacity) { - ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity)); - chunk->capacity = capacity; - chunk->size = 0; - chunk->next = chunkHead_; - chunkHead_ = chunk; - } + //! Creates a new chunk. + /*! \param capacity Capacity of the chunk in bytes. + */ + void AddChunk(size_t capacity) { + ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity)); + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + } - static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. - //! Chunk header for perpending to each chunk. - /*! Chunks are stored as a singly linked list. - */ - struct ChunkHeader { - size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). - size_t size; //!< Current size of allocated memory in bytes. - ChunkHeader *next; //!< Next chunk in the linked list. - }; + //! Chunk header for perpending to each chunk. + /*! Chunks are stored as a singly linked list. + */ + struct ChunkHeader { + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). + size_t size; //!< Current size of allocated memory in bytes. + ChunkHeader *next; //!< Next chunk in the linked list. + }; - ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. - size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. - void *userBuffer_; //!< User supplied buffer. - BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. - BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. + void *userBuffer_; //!< User supplied buffer. + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. }; } // namespace rapidjson diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 1aae685..880b040 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1,9 +1,29 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_ #include "reader.h" #include "internal/strfunc.h" -#include // placement new +#include // placement new #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH @@ -26,130 +46,130 @@ class GenericValue; //! Name-value pair in a JSON object value. /*! - This class was internal to GenericValue. It used to be a inner struct. - But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. - https://code.google.com/p/rapidjson/issues/detail?id=64 + This class was internal to GenericValue. It used to be a inner struct. + But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. + https://code.google.com/p/rapidjson/issues/detail?id=64 */ template struct GenericMember { - GenericValue name; //!< name of member (must be a string) - GenericValue value; //!< value of member. + GenericValue name; //!< name of member (must be a string) + GenericValue value; //!< value of member. }; #ifndef RAPIDJSON_NOMEMBERITERATORCLASS //! (Constant) member iterator for a JSON object value /*! - \tparam Const Is this a constant iterator? - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. + \tparam Const Is this a constant iterator? + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. - This class implements a Random Access Iterator for GenericMember elements - of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. + This class implements a Random Access Iterator for GenericMember elements + of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. - \note This iterator implementation is mainly intended to avoid implicit - conversions from iterator values to \c NULL, - e.g. from GenericValue::FindMember. + \note This iterator implementation is mainly intended to avoid implicit + conversions from iterator values to \c NULL, + e.g. from GenericValue::FindMember. - \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a - pointer-based implementation, if your platform doesn't provide - the C++ header. + \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a + pointer-based implementation, if your platform doesn't provide + the C++ header. - \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator + \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template class GenericMemberIterator - : public std::iterator >::Type> { + : public std::iterator >::Type> { - friend class GenericValue; - template friend class GenericMemberIterator; + friend class GenericValue; + template friend class GenericMemberIterator; - typedef GenericMember PlainType; - typedef typename internal::MaybeAddConst::Type ValueType; - typedef std::iterator BaseType; + typedef GenericMember PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef std::iterator BaseType; public: - //! Iterator type itself - typedef GenericMemberIterator Iterator; - //! Constant iterator type - typedef GenericMemberIterator ConstType; - //! Non-constant iterator type - typedef GenericMemberIterator NonConstType; + //! Iterator type itself + typedef GenericMemberIterator Iterator; + //! Constant iterator type + typedef GenericMemberIterator ConstType; + //! Non-constant iterator type + typedef GenericMemberIterator NonConstType; - //! Pointer to (const) GenericMember - typedef typename BaseType::pointer Pointer; - //! Reference to (const) GenericMember - typedef typename BaseType::reference Reference; - //! Signed integer type (e.g. \c ptrdiff_t) - typedef typename BaseType::difference_type DifferenceType; + //! Pointer to (const) GenericMember + typedef typename BaseType::pointer Pointer; + //! Reference to (const) GenericMember + typedef typename BaseType::reference Reference; + //! Signed integer type (e.g. \c ptrdiff_t) + typedef typename BaseType::difference_type DifferenceType; - //! Default constructor (singular value) - /*! Creates an iterator pointing to no element. - \note All operations, except for comparisons, are undefined on such values. - */ - GenericMemberIterator() : ptr_() {} + //! Default constructor (singular value) + /*! Creates an iterator pointing to no element. + \note All operations, except for comparisons, are undefined on such values. + */ + GenericMemberIterator() : ptr_() {} - //! Iterator conversions to more const - /*! - \param it (Non-const) iterator to copy from + //! Iterator conversions to more const + /*! + \param it (Non-const) iterator to copy from - Allows the creation of an iterator from another GenericMemberIterator - that is "less const". Especially, creating a non-constant iterator - from a constant iterator are disabled: - \li const -> non-const (not ok) - \li const -> const (ok) - \li non-const -> const (ok) - \li non-const -> non-const (ok) + Allows the creation of an iterator from another GenericMemberIterator + that is "less const". Especially, creating a non-constant iterator + from a constant iterator are disabled: + \li const -> non-const (not ok) + \li const -> const (ok) + \li non-const -> const (ok) + \li non-const -> non-const (ok) - \note If the \c Const template parameter is already \c false, this - constructor effectively defines a regular copy-constructor. - Otherwise, the copy constructor is implicitly defined. - */ - GenericMemberIterator(const NonConstType & it) : ptr_( it.ptr_ ) {} + \note If the \c Const template parameter is already \c false, this + constructor effectively defines a regular copy-constructor. + Otherwise, the copy constructor is implicitly defined. + */ + GenericMemberIterator(const NonConstType & it) : ptr_( it.ptr_ ) {} - //! @name stepping - //@{ - Iterator& operator++(){ ++ptr_; return *this; } - Iterator& operator--(){ --ptr_; return *this; } - Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } - Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } - //@} + //! @name stepping + //@{ + Iterator& operator++(){ ++ptr_; return *this; } + Iterator& operator--(){ --ptr_; return *this; } + Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } + Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } + //@} - //! @name increment/decrement - //@{ - Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } - Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } + //! @name increment/decrement + //@{ + Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } + Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } - Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } - Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } - //@} + Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } + Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } + //@} - //! @name relations - //@{ - bool operator==(Iterator that) const { return ptr_ == that.ptr_; } - bool operator!=(Iterator that) const { return ptr_ != that.ptr_; } - bool operator<=(Iterator that) const { return ptr_ <= that.ptr_; } - bool operator>=(Iterator that) const { return ptr_ >= that.ptr_; } - bool operator< (Iterator that) const { return ptr_ < that.ptr_; } - bool operator> (Iterator that) const { return ptr_ > that.ptr_; } - //@} + //! @name relations + //@{ + bool operator==(Iterator that) const { return ptr_ == that.ptr_; } + bool operator!=(Iterator that) const { return ptr_ != that.ptr_; } + bool operator<=(Iterator that) const { return ptr_ <= that.ptr_; } + bool operator>=(Iterator that) const { return ptr_ >= that.ptr_; } + bool operator< (Iterator that) const { return ptr_ < that.ptr_; } + bool operator> (Iterator that) const { return ptr_ > that.ptr_; } + //@} - //! @name dereference - //@{ - Reference operator*() const { return *ptr_; } - Pointer operator->() const { return ptr_; } - Reference operator[](DifferenceType n) const { return ptr_[n]; } - //@} + //! @name dereference + //@{ + Reference operator*() const { return *ptr_; } + Pointer operator->() const { return ptr_; } + Reference operator[](DifferenceType n) const { return ptr_[n]; } + //@} - //! Distance - DifferenceType operator-(Iterator that) const { return ptr_-that.ptr_; } + //! Distance + DifferenceType operator-(Iterator that) const { return ptr_-that.ptr_; } private: - //! Internal constructor from plain pointer - explicit GenericMemberIterator(Pointer p) : ptr_(p) {} + //! Internal constructor from plain pointer + explicit GenericMemberIterator(Pointer p) : ptr_(p) {} - Pointer ptr_; //!< raw pointer + Pointer ptr_; //!< raw pointer }; #else // RAPIDJSON_NOMEMBERITERATORCLASS @@ -162,14 +182,14 @@ struct GenericMemberIterator; //! non-const GenericMemberIterator template struct GenericMemberIterator { - //! use plain pointer as iterator type - typedef GenericMember* Iterator; + //! use plain pointer as iterator type + typedef GenericMember* Iterator; }; //! const GenericMemberIterator template struct GenericMemberIterator { - //! use plain const pointer as iterator type - typedef const GenericMember* Iterator; + //! use plain const pointer as iterator type + typedef const GenericMember* Iterator; }; #endif // RAPIDJSON_NOMEMBERITERATORCLASS @@ -179,143 +199,143 @@ struct GenericMemberIterator { //! Reference to a constant string (not taking a copy) /*! - \tparam CharType character type of the string + \tparam CharType character type of the string - This helper class is used to automatically infer constant string - references for string literals, especially from \c const \b (!) - character arrays. + This helper class is used to automatically infer constant string + references for string literals, especially from \c const \b (!) + character arrays. - The main use is for creating JSON string values without copying the - source string via an \ref Allocator. This requires that the referenced - string pointers have a sufficient lifetime, which exceeds the lifetime - of the associated GenericValue. + The main use is for creating JSON string values without copying the + source string via an \ref Allocator. This requires that the referenced + string pointers have a sufficient lifetime, which exceeds the lifetime + of the associated GenericValue. - \b Example - \code - Value v("foo"); // ok, no need to copy & calculate length - const char foo[] = "foo"; - v.SetString(foo); // ok + \b Example + \code + Value v("foo"); // ok, no need to copy & calculate length + const char foo[] = "foo"; + v.SetString(foo); // ok - const char* bar = foo; - // Value x(bar); // not ok, can't rely on bar's lifetime - Value x(StringRef(bar)); // lifetime explicitly guaranteed by user - Value y(StringRef(bar, 3)); // ok, explicitly pass length - \endcode + const char* bar = foo; + // Value x(bar); // not ok, can't rely on bar's lifetime + Value x(StringRef(bar)); // lifetime explicitly guaranteed by user + Value y(StringRef(bar, 3)); // ok, explicitly pass length + \endcode - \see StringRef, GenericValue::SetString + \see StringRef, GenericValue::SetString */ template struct GenericStringRef { - typedef CharType Ch; //!< character type of the string + typedef CharType Ch; //!< character type of the string - //! Create string reference from \c const character array - /*! - This constructor implicitly creates a constant string reference from - a \c const character array. It has better performance than - \ref StringRef(const CharType*) by inferring the string \ref length - from the array length, and also supports strings containing null - characters. + //! Create string reference from \c const character array + /*! + This constructor implicitly creates a constant string reference from + a \c const character array. It has better performance than + \ref StringRef(const CharType*) by inferring the string \ref length + from the array length, and also supports strings containing null + characters. - \tparam N length of the string, automatically inferred + \tparam N length of the string, automatically inferred - \param str Constant character array, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue + \param str Constant character array, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue - \post \ref s == str + \post \ref s == str - \note Constant complexity. - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ - template - GenericStringRef(const CharType (&str)[N]) - : s(str), length(N-1) {} + \note Constant complexity. + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ + template + GenericStringRef(const CharType (&str)[N]) + : s(str), length(N-1) {} - //! Explicitly create string reference from \c const character pointer - /*! - This constructor can be used to \b explicitly create a reference to - a constant string pointer. + //! Explicitly create string reference from \c const character pointer + /*! + This constructor can be used to \b explicitly create a reference to + a constant string pointer. - \see StringRef(const CharType*) + \see StringRef(const CharType*) - \param str Constant character pointer, lifetime assumed to be longer - than the use of the string in e.g. a GenericValue + \param str Constant character pointer, lifetime assumed to be longer + than the use of the string in e.g. a GenericValue - \post \ref s == str + \post \ref s == str - \note There is a hidden, private overload to disallow references to - non-const character arrays to be created via this constructor. - By this, e.g. function-scope arrays used to be filled via - \c snprintf are excluded from consideration. - In such cases, the referenced string should be \b copied to the - GenericValue instead. - */ - explicit GenericStringRef(const CharType* str) - : s(str), length(internal::StrLen(str)){} + \note There is a hidden, private overload to disallow references to + non-const character arrays to be created via this constructor. + By this, e.g. function-scope arrays used to be filled via + \c snprintf are excluded from consideration. + In such cases, the referenced string should be \b copied to the + GenericValue instead. + */ + explicit GenericStringRef(const CharType* str) + : s(str), length(internal::StrLen(str)){} - //! Create constant string reference from pointer and length - /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param len length of the string, excluding the trailing NULL terminator + //! Create constant string reference from pointer and length + /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param len length of the string, excluding the trailing NULL terminator - \post \ref s == str && \ref length == len - \note Constant complexity. - */ - GenericStringRef(const CharType* str, SizeType len) - : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } + \post \ref s == str && \ref length == len + \note Constant complexity. + */ + GenericStringRef(const CharType* str, SizeType len) + : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } - //! implicit conversion to plain CharType pointer - operator const Ch *() const { return s; } + //! implicit conversion to plain CharType pointer + operator const Ch *() const { return s; } - const Ch* const s; //!< plain CharType pointer - const SizeType length; //!< length of the string (excluding the trailing NULL terminator) + const Ch* const s; //!< plain CharType pointer + const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: - //! Disallow copy-assignment - GenericStringRef operator=(const GenericStringRef&); - //! Disallow construction from non-const array - template - GenericStringRef(CharType (&str)[N]) /* = delete */; + //! Disallow copy-assignment + GenericStringRef operator=(const GenericStringRef&); + //! Disallow construction from non-const array + template + GenericStringRef(CharType (&str)[N]) /* = delete */; }; //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. - \tparam CharType Character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \return GenericStringRef string reference object - \relatesalso GenericStringRef + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. + \tparam CharType Character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \return GenericStringRef string reference object + \relatesalso GenericStringRef - \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember + \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember */ template inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str, internal::StrLen(str)); + return GenericStringRef(str, internal::StrLen(str)); } //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function - can be used to avoid copying a character string to be referenced as a - value in a JSON GenericValue object, if the string's lifetime is known - to be valid long enough. + can be used to avoid copying a character string to be referenced as a + value in a JSON GenericValue object, if the string's lifetime is known + to be valid long enough. - This version has better performance with supplied length, and also - supports string containing null characters. + This version has better performance with supplied length, and also + supports string containing null characters. - \tparam CharType character type of the string - \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue - \param length The length of source string. - \return GenericStringRef string reference object - \relatesalso GenericStringRef + \tparam CharType character type of the string + \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue + \param length The length of source string. + \return GenericStringRef string reference object + \relatesalso GenericStringRef */ template inline GenericStringRef StringRef(const CharType* str, size_t length) { - return GenericStringRef(str, SizeType(length)); + return GenericStringRef(str, SizeType(length)); } /////////////////////////////////////////////////////////////////////////////// @@ -323,1057 +343,1057 @@ inline GenericStringRef StringRef(const CharType* str, size_t length) //! Represents a JSON value. Use Value for UTF8 encoding and default allocator. /*! - A JSON value can be one of 7 types. This class is a variant type supporting - these types. + A JSON value can be one of 7 types. This class is a variant type supporting + these types. - Use the Value if UTF8 and default allocator + Use the Value if UTF8 and default allocator - \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) - \tparam Allocator Allocator type for allocating memory of object, array and string. + \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) + \tparam Allocator Allocator type for allocating memory of object, array and string. */ #pragma pack (push, 4) template > class GenericValue { public: - //! Name-value pair in an object. - typedef GenericMember Member; - typedef Encoding EncodingType; //!< Encoding type from template parameter. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericStringRef StringRefType; //!< Reference to a constant string - typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. - typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. - typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. - typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. + //! Name-value pair in an object. + typedef GenericMember Member; + typedef Encoding EncodingType; //!< Encoding type from template parameter. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericStringRef StringRefType; //!< Reference to a constant string + typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. + typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. + typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. + typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. - //!@name Constructors and destructor. - //@{ + //!@name Constructors and destructor. + //@{ - //! Default constructor creates a null value. - GenericValue() : data_(), flags_(kNullFlag) {} + //! Default constructor creates a null value. + GenericValue() : data_(), flags_(kNullFlag) {} private: - //! Copy constructor is not permitted. - GenericValue(const GenericValue& rhs); + //! Copy constructor is not permitted. + GenericValue(const GenericValue& rhs); public: - //! Constructor with JSON value type. - /*! This creates a Value of specified type with default content. - \param type Type of the value. - \note Default content for number is zero. - */ - GenericValue(Type type) : data_(), flags_() { - static const unsigned defaultFlags[7] = { - kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag, - kNumberAnyFlag - }; - RAPIDJSON_ASSERT(type <= kNumberType); - flags_ = defaultFlags[type]; - } + //! Constructor with JSON value type. + /*! This creates a Value of specified type with default content. + \param type Type of the value. + \note Default content for number is zero. + */ + GenericValue(Type type) : data_(), flags_() { + static const unsigned defaultFlags[7] = { + kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kConstStringFlag, + kNumberAnyFlag + }; + RAPIDJSON_ASSERT(type <= kNumberType); + flags_ = defaultFlags[type]; + } - //! Explicit copy constructor (with allocator) - /*! Creates a copy of a Value by using the given Allocator - \tparam SourceAllocator allocator of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). - \see CopyFrom() - */ - template< typename SourceAllocator > - GenericValue(const GenericValue& rhs, Allocator & allocator); + //! Explicit copy constructor (with allocator) + /*! Creates a copy of a Value by using the given Allocator + \tparam SourceAllocator allocator of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \see CopyFrom() + */ + template< typename SourceAllocator > + GenericValue(const GenericValue& rhs, Allocator & allocator); - //! Constructor for boolean value. - /*! \param b Boolean value - \note This constructor is limited to \em real boolean values and rejects - implicitly converted types like arbitrary pointers. Use an explicit cast - to \c bool, if you want to construct a boolean JSON value in such cases. - */ + //! Constructor for boolean value. + /*! \param b Boolean value + \note This constructor is limited to \em real boolean values and rejects + implicitly converted types like arbitrary pointers. Use an explicit cast + to \c bool, if you want to construct a boolean JSON value in such cases. + */ #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen - template - explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) + template + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) #else - explicit GenericValue(bool b) + explicit GenericValue(bool b) #endif - : data_(), flags_(b ? kTrueFlag : kFalseFlag) {} - - //! Constructor for int value. - explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) { - data_.n.i64 = i; - if (i >= 0) - flags_ |= kUintFlag | kUint64Flag; - } - - //! Constructor for unsigned value. - explicit GenericValue(unsigned u) : data_(), flags_(kNumberUintFlag) { - data_.n.u64 = u; - if (!(u & 0x80000000)) - flags_ |= kIntFlag | kInt64Flag; - } - - //! Constructor for int64_t value. - explicit GenericValue(int64_t i64) : data_(), flags_(kNumberInt64Flag) { - data_.n.i64 = i64; - if (i64 >= 0) { - flags_ |= kNumberUint64Flag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - flags_ |= kUintFlag; - if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - flags_ |= kIntFlag; - } - else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - flags_ |= kIntFlag; - } - - //! Constructor for uint64_t value. - explicit GenericValue(uint64_t u64) : data_(), flags_(kNumberUint64Flag) { - data_.n.u64 = u64; - if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) - flags_ |= kInt64Flag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - flags_ |= kUintFlag; - if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - flags_ |= kIntFlag; - } - - //! Constructor for double value. - explicit GenericValue(double d) : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } - - //! Constructor for constant string (i.e. do not make a copy of string) - GenericValue(const Ch* s, SizeType length) : data_(), flags_() { SetStringRaw(StringRef(s, length)); } - - //! Constructor for constant string (i.e. do not make a copy of string) - explicit GenericValue(StringRefType s) : data_(), flags_() { SetStringRaw(s); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); } - - //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } - - //! Destructor. - /*! Need to destruct elements of array, members of object, or copy-string. - */ - ~GenericValue() { - if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - switch(flags_) { - case kArrayFlag: - for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) - v->~GenericValue(); - Allocator::Free(data_.a.elements); - break; - - case kObjectFlag: - for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - m->~GenericMember(); - } - Allocator::Free(data_.o.members); - break; - - case kCopyStringFlag: - Allocator::Free(const_cast(data_.s.str)); - break; - - default: - break; // Do nothing for other types. - } - } - } - - //@} - - //!@name Assignment operators - //@{ - - //! Assignment with move semantics. - /*! \param rhs Source of the assignment. It will become a null value after assignment. - */ - GenericValue& operator=(GenericValue& rhs) { - RAPIDJSON_ASSERT(this != &rhs); - this->~GenericValue(); - RawAssign(rhs); - return *this; - } - - //! Assignment of constant string reference (no copy) - /*! \param str Constant string reference to be assigned - \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. - \see GenericStringRef, operator=(T) - */ - GenericValue& operator=(StringRefType str) { - GenericValue s(str); - return *this = s; - } - - //! Assignment with primitive types. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value The value to be assigned. - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref SetString(const Ch*, Allocator&) (for copying) or - \ref StringRef() (to explicitly mark the pointer as constant) instead. - All other pointer types would implicitly convert to \c bool, - use \ref SetBool() instead. - */ - template - RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) - operator=(T value) { - GenericValue v(value); - return *this = v; - } - - //! Deep-copy assignment from Value - /*! Assigns a \b copy of the Value to the current Value object - \tparam SourceAllocator Allocator type of \c rhs - \param rhs Value to copy from (read-only) - \param allocator Allocator to use for copying - */ - template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { - RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); - this->~GenericValue(); - new (this) GenericValue(rhs,allocator); - return *this; - } - - //! Exchange the contents of this value with those of other. - /*! - \param other Another value. - \note Constant complexity. - */ - GenericValue& Swap(GenericValue& other) { - GenericValue temp; - temp.RawAssign(*this); - RawAssign(other); - other.RawAssign(temp); - return *this; - } - - //! Prepare Value for move semantics - /*! \return *this */ - GenericValue& Move() { return *this; } - //@} - - //!@name Equal-to and not-equal-to operators - //@{ - //! Equal-to operator - /*! - \note If an object contains duplicated named member, comparing equality with any object is always \c false. - \note Linear time complexity (number of all values in the subtree and total lengths of all strings). - */ - bool operator==(const GenericValue& rhs) const { - if (GetType() != rhs.GetType()) - return false; - - switch (GetType()) { - case kObjectType: // Warning: O(n^2) inner-loop - if (data_.o.size != rhs.data_.o.size) - return false; - for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { - ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); - if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) - return false; - } - return true; - - case kArrayType: - if (data_.a.size != rhs.data_.a.size) - return false; - for (SizeType i = 0; i < data_.a.size; i++) - if ((*this)[i] != rhs[i]) - return false; - return true; - - case kStringType: - return StringEqual(rhs); - - case kNumberType: - if (IsDouble() || rhs.GetDouble()) - return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double. - else - return data_.n.u64 == rhs.data_.n.u64; - - default: // kTrueType, kFalseType, kNullType - return true; - } - } - - //! Not-equal-to operator - bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } - - //! (Not-)Equal-to operator with const C-string pointer. - friend bool operator==(const GenericValue& lhs, const Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); } - friend bool operator!=(const GenericValue& lhs, const Ch* rhs) { return !(lhs == rhs); } - friend bool operator==(const Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; } - friend bool operator!=(const Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); } - - //! (Not-)Equal-to operator with non-const C-string pointer. - friend bool operator==(const GenericValue& lhs, Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); } - friend bool operator!=(const GenericValue& lhs, Ch* rhs) { return !(lhs == rhs); } - friend bool operator==(Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; } - friend bool operator!=(Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); } - - //! (Not-)Equal-to operator with primitive types. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false - */ - template friend bool operator==(const GenericValue& lhs, const T& rhs) { return lhs == GenericValue(rhs); } - template friend bool operator!=(const GenericValue& lhs, const T& rhs) { return !(lhs == rhs); } - template friend bool operator==(const T& lhs, const GenericValue& rhs) { return GenericValue(lhs) == rhs; } - template friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(lhs == rhs); } - //@} - - //!@name Type - //@{ - - Type GetType() const { return static_cast(flags_ & kTypeMask); } - bool IsNull() const { return flags_ == kNullFlag; } - bool IsFalse() const { return flags_ == kFalseFlag; } - bool IsTrue() const { return flags_ == kTrueFlag; } - bool IsBool() const { return (flags_ & kBoolFlag) != 0; } - bool IsObject() const { return flags_ == kObjectFlag; } - bool IsArray() const { return flags_ == kArrayFlag; } - bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } - bool IsInt() const { return (flags_ & kIntFlag) != 0; } - bool IsUint() const { return (flags_ & kUintFlag) != 0; } - bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } - bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } - bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } - bool IsString() const { return (flags_ & kStringFlag) != 0; } - - //@} - - //!@name Null - //@{ - - GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } - - //@} - - //!@name Bool - //@{ - - bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } - //!< Set boolean value - /*! \post IsBool() == true */ - GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } - - //@} - - //!@name Object - //@{ - - //! Set this value as an empty object. - /*! \post IsObject() == true */ - GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } - - //! Get the value associated with the name. - /*! - \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. - Since 0.2, if the name is not correct, it will assert. - If user is unsure whether a member exists, user should use HasMember() first. - A better approach is to use FindMember(). - \note Linear time complexity. - */ - GenericValue& operator[](const Ch* name) { - GenericValue n(StringRef(name)); - return (*this)[n]; - } - const GenericValue& operator[](const Ch* name) const { return const_cast(*this)[name]; } - - // This version is faster because it does not need a StrLen(). - // It can also handle string with null character. - GenericValue& operator[](const GenericValue& name) { - MemberIterator member = FindMember(name); - if (member != MemberEnd()) - return member->value; - else { - RAPIDJSON_ASSERT(false); // see above note - static GenericValue NullValue; - return NullValue; - } - } - const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } - - //! Const member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } - //! Const \em past-the-end member iterator - /*! \pre IsObject() == true */ - ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); } - //! Member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); } - //! \em Past-the-end member iterator - /*! \pre IsObject() == true */ - MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); } - - //! Check whether a member exists in the object. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } - - //! Check whether a member exists in the object with GenericValue name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Whether a member with that name exists. - \note It is better to use FindMember() directly if you need the obtain the value as well. - \note Linear time complexity. - */ - bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } - - //! Find member by name. - /*! - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - MemberIterator FindMember(const Ch* name) { - GenericValue n(StringRef(name)); - return FindMember(n); - } - - ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } - - //! Find member by name. - /*! - This version is faster because it does not need a StrLen(). It can also handle string with null character. - \param name Member name to be searched. - \pre IsObject() == true - \return Iterator to member, if it exists. - Otherwise returns \ref MemberEnd(). - - \note Earlier versions of Rapidjson returned a \c NULL pointer, in case - the requested member doesn't exist. For consistency with e.g. - \c std::map, this has been changed to MemberEnd() now. - \note Linear time complexity. - */ - MemberIterator FindMember(const GenericValue& name) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - MemberIterator member = MemberBegin(); - for ( ; member != MemberEnd(); ++member) - if (name.StringEqual(member->name)) - break; - return member; - } - ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } - - //! Add a member (name-value pair) to the object. - /*! \param name A string value as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c name and \c value will be transferred to this object on success. - \pre IsObject() && name.IsString() - \post name.IsNull() && value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(name.IsString()); - - Object& o = data_.o; - if (o.size >= o.capacity) { - if (o.capacity == 0) { - o.capacity = kDefaultObjectCapacity; - o.members = reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member))); - } - else { - SizeType oldCapacity = o.capacity; - o.capacity *= 2; - o.members = reinterpret_cast(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member))); - } - } - o.members[o.size].name.RawAssign(name); - o.members[o.size].value.RawAssign(value); - o.size++; - return *this; - } - - //! Add a member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value Value of any type. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this object on success. - \pre IsObject() - \post value.IsNull() - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { - GenericValue n(name); - return AddMember(n, value, allocator); - } - - //! Add a constant string value as member (name-value pair) to the object. - /*! \param name A constant string reference as name of member. - \param value constant string reference as value of member. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. - \note Amortized Constant time complexity. - */ - GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { - GenericValue v(value); - return AddMember(name, v, allocator); - } - - //! Add any primitive value as member (name-value pair) to the object. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param name A constant string reference as name of member. - \param value Value of primitive type \c T as value of member - \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \pre IsObject() - - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref - AddMember(StringRefType, StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized Constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) - AddMember(StringRefType name, T value, Allocator& allocator) { - GenericValue n(name); - GenericValue v(value); - return AddMember(n, v, allocator); - } - - //! Remove a member in object by its name. - /*! \param name Name of member to be removed. - \return Whether the member existed. - \note Removing member is implemented by moving the last member. So the ordering of members is changed. - \note Linear time complexity. - */ - bool RemoveMember(const Ch* name) { - GenericValue n(StringRef(name)); - return RemoveMember(n); - } - - bool RemoveMember(const GenericValue& name) { - MemberIterator m = FindMember(name); - if (m != MemberEnd()) { - RemoveMember(m); - return true; - } - else - return false; - } - - //! Remove a member in object by iterator. - /*! \param m member iterator (obtained by FindMember() or MemberBegin()). - \return the new iterator after removal. - \note Removing member is implemented by moving the last member. So the ordering of members is changed. - \note Use \ref EraseMember(ConstMemberIterator) instead, if you need to rely on a stable member ordering. - \note Constant time complexity. - */ - MemberIterator RemoveMember(MemberIterator m) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(data_.o.members != 0); - RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - - MemberIterator last(data_.o.members + (data_.o.size - 1)); - if (data_.o.size > 1 && m != last) { - // Move the last one to this place - *m = *last; - } - else { - // Only one left, just destroy - m->~GenericMember(); - } - --data_.o.size; - return m; - } - - //! Remove a member from an object by iterator. - /*! \param pos iterator to the member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() - \return Iterator following the removed element. - If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. - \note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members. - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator pos) { - return EraseMember(pos, pos +1); - } - - //! Remove members in the range [first, last) from an object. - /*! \param first iterator to the first member to remove - \param last iterator following the last member to remove - \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() - \return Iterator following the last removed element. - \note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members. - \note Linear time complexity. - */ - MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { - RAPIDJSON_ASSERT(IsObject()); - RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(data_.o.members != 0); - RAPIDJSON_ASSERT(first >= MemberBegin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= MemberEnd()); - - MemberIterator pos = MemberBegin() + (first - MemberBegin()); - for (MemberIterator itr = pos; ConstMemberIterator(itr) != last; ++itr) - itr->~Member(); - memmove(&*pos, &*last, (ConstMemberIterator(MemberEnd()) - last) * sizeof(Member)); - data_.o.size -= (last - first); - return pos; - } - - //@} - - //!@name Array - //@{ - - //! Set this value as an empty array. - /*! \post IsArray == true */ - GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } - - //! Get the number of elements in array. - SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } - - //! Get the capacity of array. - SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } - - //! Check whether the array is empty. - bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } - - //! Remove all elements in the array. - /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. - \note Linear time complexity. - */ - void Clear() { - RAPIDJSON_ASSERT(IsArray()); - for (SizeType i = 0; i < data_.a.size; ++i) - data_.a.elements[i].~GenericValue(); - data_.a.size = 0; - } - - //! Get an element from array by index. - /*! \param index Zero-based index of element. + : data_(), flags_(b ? kTrueFlag : kFalseFlag) {} + + //! Constructor for int value. + explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) { + data_.n.i64 = i; + if (i >= 0) + flags_ |= kUintFlag | kUint64Flag; + } + + //! Constructor for unsigned value. + explicit GenericValue(unsigned u) : data_(), flags_(kNumberUintFlag) { + data_.n.u64 = u; + if (!(u & 0x80000000)) + flags_ |= kIntFlag | kInt64Flag; + } + + //! Constructor for int64_t value. + explicit GenericValue(int64_t i64) : data_(), flags_(kNumberInt64Flag) { + data_.n.i64 = i64; + if (i64 >= 0) { + flags_ |= kNumberUint64Flag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + flags_ |= kUintFlag; + if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + flags_ |= kIntFlag; + } + else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + flags_ |= kIntFlag; + } + + //! Constructor for uint64_t value. + explicit GenericValue(uint64_t u64) : data_(), flags_(kNumberUint64Flag) { + data_.n.u64 = u64; + if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) + flags_ |= kInt64Flag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) + flags_ |= kUintFlag; + if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) + flags_ |= kIntFlag; + } + + //! Constructor for double value. + explicit GenericValue(double d) : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } + + //! Constructor for constant string (i.e. do not make a copy of string) + GenericValue(const Ch* s, SizeType length) : data_(), flags_() { SetStringRaw(StringRef(s, length)); } + + //! Constructor for constant string (i.e. do not make a copy of string) + explicit GenericValue(StringRefType s) : data_(), flags_() { SetStringRaw(s); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); } + + //! Constructor for copy-string (i.e. do make a copy of string) + GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } + + //! Destructor. + /*! Need to destruct elements of array, members of object, or copy-string. + */ + ~GenericValue() { + if (Allocator::kNeedFree) { // Shortcut by Allocator's trait + switch(flags_) { + case kArrayFlag: + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(data_.a.elements); + break; + + case kObjectFlag: + for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { + m->~GenericMember(); + } + Allocator::Free(data_.o.members); + break; + + case kCopyStringFlag: + Allocator::Free(const_cast(data_.s.str)); + break; + + default: + break; // Do nothing for other types. + } + } + } + + //@} + + //!@name Assignment operators + //@{ + + //! Assignment with move semantics. + /*! \param rhs Source of the assignment. It will become a null value after assignment. + */ + GenericValue& operator=(GenericValue& rhs) { + RAPIDJSON_ASSERT(this != &rhs); + this->~GenericValue(); + RawAssign(rhs); + return *this; + } + + //! Assignment of constant string reference (no copy) + /*! \param str Constant string reference to be assigned + \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. + \see GenericStringRef, operator=(T) + */ + GenericValue& operator=(StringRefType str) { + GenericValue s(str); + return *this = s; + } + + //! Assignment with primitive types. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value The value to be assigned. + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref SetString(const Ch*, Allocator&) (for copying) or + \ref StringRef() (to explicitly mark the pointer as constant) instead. + All other pointer types would implicitly convert to \c bool, + use \ref SetBool() instead. + */ + template + RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) + operator=(T value) { + GenericValue v(value); + return *this = v; + } + + //! Deep-copy assignment from Value + /*! Assigns a \b copy of the Value to the current Value object + \tparam SourceAllocator Allocator type of \c rhs + \param rhs Value to copy from (read-only) + \param allocator Allocator to use for copying + */ + template + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { + RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); + this->~GenericValue(); + new (this) GenericValue(rhs,allocator); + return *this; + } + + //! Exchange the contents of this value with those of other. + /*! + \param other Another value. + \note Constant complexity. + */ + GenericValue& Swap(GenericValue& other) { + GenericValue temp; + temp.RawAssign(*this); + RawAssign(other); + other.RawAssign(temp); + return *this; + } + + //! Prepare Value for move semantics + /*! \return *this */ + GenericValue& Move() { return *this; } + //@} + + //!@name Equal-to and not-equal-to operators + //@{ + //! Equal-to operator + /*! + \note If an object contains duplicated named member, comparing equality with any object is always \c false. + \note Linear time complexity (number of all values in the subtree and total lengths of all strings). + */ + bool operator==(const GenericValue& rhs) const { + if (GetType() != rhs.GetType()) + return false; + + switch (GetType()) { + case kObjectType: // Warning: O(n^2) inner-loop + if (data_.o.size != rhs.data_.o.size) + return false; + for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { + ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); + if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) + return false; + } + return true; + + case kArrayType: + if (data_.a.size != rhs.data_.a.size) + return false; + for (SizeType i = 0; i < data_.a.size; i++) + if ((*this)[i] != rhs[i]) + return false; + return true; + + case kStringType: + return StringEqual(rhs); + + case kNumberType: + if (IsDouble() || rhs.GetDouble()) + return GetDouble() == rhs.GetDouble(); // May convert one operand from integer to double. + else + return data_.n.u64 == rhs.data_.n.u64; + + default: // kTrueType, kFalseType, kNullType + return true; + } + } + + //! Not-equal-to operator + bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } + + //! (Not-)Equal-to operator with const C-string pointer. + friend bool operator==(const GenericValue& lhs, const Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); } + friend bool operator!=(const GenericValue& lhs, const Ch* rhs) { return !(lhs == rhs); } + friend bool operator==(const Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; } + friend bool operator!=(const Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); } + + //! (Not-)Equal-to operator with non-const C-string pointer. + friend bool operator==(const GenericValue& lhs, Ch* rhs) { return lhs == GenericValue(StringRef(rhs)); } + friend bool operator!=(const GenericValue& lhs, Ch* rhs) { return !(lhs == rhs); } + friend bool operator==(Ch* lhs, const GenericValue& rhs) { return GenericValue(StringRef(lhs)) == rhs; } + friend bool operator!=(Ch* lhs, const GenericValue& rhs) { return !(lhs == rhs); } + + //! (Not-)Equal-to operator with primitive types. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false + */ + template friend bool operator==(const GenericValue& lhs, const T& rhs) { return lhs == GenericValue(rhs); } + template friend bool operator!=(const GenericValue& lhs, const T& rhs) { return !(lhs == rhs); } + template friend bool operator==(const T& lhs, const GenericValue& rhs) { return GenericValue(lhs) == rhs; } + template friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(lhs == rhs); } + //@} + + //!@name Type + //@{ + + Type GetType() const { return static_cast(flags_ & kTypeMask); } + bool IsNull() const { return flags_ == kNullFlag; } + bool IsFalse() const { return flags_ == kFalseFlag; } + bool IsTrue() const { return flags_ == kTrueFlag; } + bool IsBool() const { return (flags_ & kBoolFlag) != 0; } + bool IsObject() const { return flags_ == kObjectFlag; } + bool IsArray() const { return flags_ == kArrayFlag; } + bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } + bool IsInt() const { return (flags_ & kIntFlag) != 0; } + bool IsUint() const { return (flags_ & kUintFlag) != 0; } + bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } + bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } + bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } + bool IsString() const { return (flags_ & kStringFlag) != 0; } + + //@} + + //!@name Null + //@{ + + GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } + + //@} + + //!@name Bool + //@{ + + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } + //!< Set boolean value + /*! \post IsBool() == true */ + GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } + + //@} + + //!@name Object + //@{ + + //! Set this value as an empty object. + /*! \post IsObject() == true */ + GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } + + //! Get the value associated with the name. + /*! + \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. + Since 0.2, if the name is not correct, it will assert. + If user is unsure whether a member exists, user should use HasMember() first. + A better approach is to use FindMember(). + \note Linear time complexity. + */ + GenericValue& operator[](const Ch* name) { + GenericValue n(StringRef(name)); + return (*this)[n]; + } + const GenericValue& operator[](const Ch* name) const { return const_cast(*this)[name]; } + + // This version is faster because it does not need a StrLen(). + // It can also handle string with null character. + GenericValue& operator[](const GenericValue& name) { + MemberIterator member = FindMember(name); + if (member != MemberEnd()) + return member->value; + else { + RAPIDJSON_ASSERT(false); // see above note + static GenericValue NullValue; + return NullValue; + } + } + const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } + + //! Const member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } + //! Const \em past-the-end member iterator + /*! \pre IsObject() == true */ + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); } + //! Member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); } + //! \em Past-the-end member iterator + /*! \pre IsObject() == true */ + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); } + + //! Check whether a member exists in the object. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } + + //! Check whether a member exists in the object with GenericValue name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Whether a member with that name exists. + \note It is better to use FindMember() directly if you need the obtain the value as well. + \note Linear time complexity. + */ + bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } + + //! Find member by name. + /*! + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + MemberIterator FindMember(const Ch* name) { + GenericValue n(StringRef(name)); + return FindMember(n); + } + + ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } + + //! Find member by name. + /*! + This version is faster because it does not need a StrLen(). It can also handle string with null character. + \param name Member name to be searched. + \pre IsObject() == true + \return Iterator to member, if it exists. + Otherwise returns \ref MemberEnd(). + + \note Earlier versions of Rapidjson returned a \c NULL pointer, in case + the requested member doesn't exist. For consistency with e.g. + \c std::map, this has been changed to MemberEnd() now. + \note Linear time complexity. + */ + MemberIterator FindMember(const GenericValue& name) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + MemberIterator member = MemberBegin(); + for ( ; member != MemberEnd(); ++member) + if (name.StringEqual(member->name)) + break; + return member; + } + ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } + + //! Add a member (name-value pair) to the object. + /*! \param name A string value as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c name and \c value will be transferred to this object on success. + \pre IsObject() && name.IsString() + \post name.IsNull() && value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(name.IsString()); + + Object& o = data_.o; + if (o.size >= o.capacity) { + if (o.capacity == 0) { + o.capacity = kDefaultObjectCapacity; + o.members = reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member))); + } + else { + SizeType oldCapacity = o.capacity; + o.capacity *= 2; + o.members = reinterpret_cast(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member))); + } + } + o.members[o.size].name.RawAssign(name); + o.members[o.size].value.RawAssign(value); + o.size++; + return *this; + } + + //! Add a member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value Value of any type. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this object on success. + \pre IsObject() + \post value.IsNull() + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { + GenericValue n(name); + return AddMember(n, value, allocator); + } + + //! Add a constant string value as member (name-value pair) to the object. + /*! \param name A constant string reference as name of member. + \param value constant string reference as value of member. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. + \note Amortized Constant time complexity. + */ + GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { + GenericValue v(value); + return AddMember(name, v, allocator); + } + + //! Add any primitive value as member (name-value pair) to the object. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param name A constant string reference as name of member. + \param value Value of primitive type \c T as value of member + \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \pre IsObject() + + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref + AddMember(StringRefType, StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized Constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) + AddMember(StringRefType name, T value, Allocator& allocator) { + GenericValue n(name); + GenericValue v(value); + return AddMember(n, v, allocator); + } + + //! Remove a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Removing member is implemented by moving the last member. So the ordering of members is changed. + \note Linear time complexity. + */ + bool RemoveMember(const Ch* name) { + GenericValue n(StringRef(name)); + return RemoveMember(n); + } + + bool RemoveMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + RemoveMember(m); + return true; + } + else + return false; + } + + //! Remove a member in object by iterator. + /*! \param m member iterator (obtained by FindMember() or MemberBegin()). + \return the new iterator after removal. + \note Removing member is implemented by moving the last member. So the ordering of members is changed. + \note Use \ref EraseMember(ConstMemberIterator) instead, if you need to rely on a stable member ordering. + \note Constant time complexity. + */ + MemberIterator RemoveMember(MemberIterator m) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(data_.o.members != 0); + RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); + + MemberIterator last(data_.o.members + (data_.o.size - 1)); + if (data_.o.size > 1 && m != last) { + // Move the last one to this place + *m = *last; + } + else { + // Only one left, just destroy + m->~GenericMember(); + } + --data_.o.size; + return m; + } + + //! Remove a member from an object by iterator. + /*! \param pos iterator to the member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() + \return Iterator following the removed element. + If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. + \note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members. + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator pos) { + return EraseMember(pos, pos +1); + } + + //! Remove members in the range [first, last) from an object. + /*! \param first iterator to the first member to remove + \param last iterator following the last member to remove + \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() + \return Iterator following the last removed element. + \note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members. + \note Linear time complexity. + */ + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { + RAPIDJSON_ASSERT(IsObject()); + RAPIDJSON_ASSERT(data_.o.size > 0); + RAPIDJSON_ASSERT(data_.o.members != 0); + RAPIDJSON_ASSERT(first >= MemberBegin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= MemberEnd()); + + MemberIterator pos = MemberBegin() + (first - MemberBegin()); + for (MemberIterator itr = pos; ConstMemberIterator(itr) != last; ++itr) + itr->~Member(); + memmove(&*pos, &*last, (ConstMemberIterator(MemberEnd()) - last) * sizeof(Member)); + data_.o.size -= (last - first); + return pos; + } + + //@} + + //!@name Array + //@{ + + //! Set this value as an empty array. + /*! \post IsArray == true */ + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + + //! Get the number of elements in array. + SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } + + //! Get the capacity of array. + SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } + + //! Check whether the array is empty. + bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } + + //! Remove all elements in the array. + /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. + \note Linear time complexity. + */ + void Clear() { + RAPIDJSON_ASSERT(IsArray()); + for (SizeType i = 0; i < data_.a.size; ++i) + data_.a.elements[i].~GenericValue(); + data_.a.size = 0; + } + + //! Get an element from array by index. + /*! \param index Zero-based index of element. \code Value a(kArrayType); a.PushBack(123); -int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type. -int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work. -int z = a[0u].GetInt(); // This works too. +int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type. +int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work. +int z = a[0u].GetInt(); // This works too. \endcode - */ - GenericValue& operator[](SizeType index) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(index < data_.a.size); - return data_.a.elements[index]; - } - const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } + */ + GenericValue& operator[](SizeType index) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(index < data_.a.size); + return data_.a.elements[index]; + } + const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } - //! Element iterator - /*! \pre IsArray() == true */ - ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } - //! \em Past-the-end element iterator - /*! \pre IsArray() == true */ - ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } - //! Constant element iterator - /*! \pre IsArray() == true */ - ConstValueIterator Begin() const { return const_cast(*this).Begin(); } - //! Constant \em past-the-end element iterator - /*! \pre IsArray() == true */ - ConstValueIterator End() const { return const_cast(*this).End(); } + //! Element iterator + /*! \pre IsArray() == true */ + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } + //! \em Past-the-end element iterator + /*! \pre IsArray() == true */ + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } + //! Constant element iterator + /*! \pre IsArray() == true */ + ConstValueIterator Begin() const { return const_cast(*this).Begin(); } + //! Constant \em past-the-end element iterator + /*! \pre IsArray() == true */ + ConstValueIterator End() const { return const_cast(*this).End(); } - //! Request the array to have enough capacity to store elements. - /*! \param newCapacity The capacity that the array at least need to have. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \note Linear time complexity. - */ - GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (newCapacity > data_.a.capacity) { - data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); - data_.a.capacity = newCapacity; - } - return *this; - } + //! Request the array to have enough capacity to store elements. + /*! \param newCapacity The capacity that the array at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (newCapacity > data_.a.capacity) { + data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); + data_.a.capacity = newCapacity; + } + return *this; + } - //! Append a GenericValue at the end of the array. - /*! \param value Value to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \post value.IsNull() == true - \return The value itself for fluent API. - \note The ownership of \c value will be transferred to this array on success. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - */ - GenericValue& PushBack(GenericValue& value, Allocator& allocator) { - RAPIDJSON_ASSERT(IsArray()); - if (data_.a.size >= data_.a.capacity) - Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator); - data_.a.elements[data_.a.size++].RawAssign(value); - return *this; - } + //! Append a GenericValue at the end of the array. + /*! \param value Value to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \post value.IsNull() == true + \return The value itself for fluent API. + \note The ownership of \c value will be transferred to this array on success. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + */ + GenericValue& PushBack(GenericValue& value, Allocator& allocator) { + RAPIDJSON_ASSERT(IsArray()); + if (data_.a.size >= data_.a.capacity) + Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : data_.a.capacity * 2, allocator); + data_.a.elements[data_.a.size++].RawAssign(value); + return *this; + } - //! Append a constant string reference at the end of the array. - /*! \param value Constant string reference to be appended. - \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note Amortized constant time complexity. - \see GenericStringRef - */ - GenericValue& PushBack(StringRefType value, Allocator& allocator) { - return (*this).template PushBack(value, allocator); - } + //! Append a constant string reference at the end of the array. + /*! \param value Constant string reference to be appended. + \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + \note Amortized constant time complexity. + \see GenericStringRef + */ + GenericValue& PushBack(StringRefType value, Allocator& allocator) { + return (*this).template PushBack(value, allocator); + } - //! Append a primitive value at the end of the array. - /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t - \param value Value of primitive type T to be appended. - \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). - \pre IsArray() == true - \return The value itself for fluent API. - \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. + //! Append a primitive value at the end of the array. + /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t + \param value Value of primitive type T to be appended. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \pre IsArray() == true + \return The value itself for fluent API. + \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. - \note The source type \c T explicitly disallows all pointer types, - especially (\c const) \ref Ch*. This helps avoiding implicitly - referencing character strings with insufficient lifetime, use - \ref PushBack(GenericValue&, Allocator&) or \ref - PushBack(StringRefType, Allocator&). - All other pointer types would implicitly convert to \c bool, - use an explicit cast instead, if needed. - \note Amortized constant time complexity. - */ - template - RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) - PushBack(T value, Allocator& allocator) { - GenericValue v(value); - return PushBack(v, allocator); - } + \note The source type \c T explicitly disallows all pointer types, + especially (\c const) \ref Ch*. This helps avoiding implicitly + referencing character strings with insufficient lifetime, use + \ref PushBack(GenericValue&, Allocator&) or \ref + PushBack(StringRefType, Allocator&). + All other pointer types would implicitly convert to \c bool, + use an explicit cast instead, if needed. + \note Amortized constant time complexity. + */ + template + RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) + PushBack(T value, Allocator& allocator) { + GenericValue v(value); + return PushBack(v, allocator); + } - //! Remove the last element in the array. - /*! - \note Constant time complexity. - */ - GenericValue& PopBack() { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(!Empty()); - data_.a.elements[--data_.a.size].~GenericValue(); - return *this; - } + //! Remove the last element in the array. + /*! + \note Constant time complexity. + */ + GenericValue& PopBack() { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(!Empty()); + data_.a.elements[--data_.a.size].~GenericValue(); + return *this; + } - //! Remove an element of array by iterator. - /*! - \param pos iterator to the element to remove - \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() - \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator pos) { - return Erase(pos, pos + 1); - } + //! Remove an element of array by iterator. + /*! + \param pos iterator to the element to remove + \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() + \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator pos) { + return Erase(pos, pos + 1); + } - //! Remove elements in the range [first, last) of the array. - /*! - \param first iterator to the first element to remove - \param last iterator following the last element to remove - \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() - \return Iterator following the last removed element. - \note Linear time complexity. - */ - ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { - RAPIDJSON_ASSERT(IsArray()); - RAPIDJSON_ASSERT(data_.a.size > 0); - RAPIDJSON_ASSERT(data_.a.elements != 0); - RAPIDJSON_ASSERT(first >= Begin()); - RAPIDJSON_ASSERT(first <= last); - RAPIDJSON_ASSERT(last <= End()); - ValueIterator pos = Begin() + (first - Begin()); - for (ValueIterator itr = pos; itr != last; ++itr) - itr->~GenericValue(); - memmove(pos, last, (End() - last) * sizeof(GenericValue)); - data_.a.size -= (last - first); - return pos; - } + //! Remove elements in the range [first, last) of the array. + /*! + \param first iterator to the first element to remove + \param last iterator following the last element to remove + \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() + \return Iterator following the last removed element. + \note Linear time complexity. + */ + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { + RAPIDJSON_ASSERT(IsArray()); + RAPIDJSON_ASSERT(data_.a.size > 0); + RAPIDJSON_ASSERT(data_.a.elements != 0); + RAPIDJSON_ASSERT(first >= Begin()); + RAPIDJSON_ASSERT(first <= last); + RAPIDJSON_ASSERT(last <= End()); + ValueIterator pos = Begin() + (first - Begin()); + for (ValueIterator itr = pos; itr != last; ++itr) + itr->~GenericValue(); + memmove(pos, last, (End() - last) * sizeof(GenericValue)); + data_.a.size -= (last - first); + return pos; + } - //@} + //@} - //!@name Number - //@{ + //!@name Number + //@{ - int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; } - unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; } - int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } - uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; } + int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; } + unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; } + int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } + uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; } - double GetDouble() const { - RAPIDJSON_ASSERT(IsNumber()); - if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. - if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double - if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double - if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) - RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) - } + double GetDouble() const { + RAPIDJSON_ASSERT(IsNumber()); + if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. + if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double + if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double + if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) + } - GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } - GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } - GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } - GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } - GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } + GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } + GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } + GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } + GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } + GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } - //@} + //@} - //!@name String - //@{ + //!@name String + //@{ - const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; } + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; } - //! Get the length of string. - /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). - */ - SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; } + //! Get the length of string. + /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). + */ + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; } - //! Set this value as a string without copying source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string pointer. - \param length The length of source string, excluding the trailing null terminator. - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == length - \see SetString(StringRefType) - */ - GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } + //! Set this value as a string without copying source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string pointer. + \param length The length of source string, excluding the trailing null terminator. + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == length + \see SetString(StringRefType) + */ + GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } - //! Set this value as a string without copying source string. - /*! \param s source string reference - \return The value itself for fluent API. - \post IsString() == true && GetString() == s && GetStringLength() == s.length - */ - GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } + //! Set this value as a string without copying source string. + /*! \param s source string reference + \return The value itself for fluent API. + \post IsString() == true && GetString() == s && GetStringLength() == s.length + */ + GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } - //! Set this value as a string by copying from source string. - /*! This version has better performance with supplied length, and also support string containing null character. - \param s source string. - \param length The length of source string, excluding the trailing null terminator. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + //! Set this value as a string by copying from source string. + /*! This version has better performance with supplied length, and also support string containing null character. + \param s source string. + \param length The length of source string, excluding the trailing null terminator. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } - //! Set this value as a string by copying from source string. - /*! \param s source string. - \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). - \return The value itself for fluent API. - \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length - */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } + //! Set this value as a string by copying from source string. + /*! \param s source string. + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } - //@} + //@} - //! Generate events of this value to a Handler. - /*! This function adopts the GoF visitor pattern. - Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. - It can also be used to deep clone this value via GenericDocument, which is also a Handler. - \tparam Handler type of handler. - \param handler An object implementing concept Handler. - */ - template - bool Accept(Handler& handler) const { - switch(GetType()) { - case kNullType: return handler.Null(); - case kFalseType: return handler.Bool(false); - case kTrueType: return handler.Bool(true); + //! Generate events of this value to a Handler. + /*! This function adopts the GoF visitor pattern. + Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. + It can also be used to deep clone this value via GenericDocument, which is also a Handler. + \tparam Handler type of handler. + \param handler An object implementing concept Handler. + */ + template + bool Accept(Handler& handler) const { + switch(GetType()) { + case kNullType: return handler.Null(); + case kFalseType: return handler.Bool(false); + case kTrueType: return handler.Bool(true); - case kObjectType: - if (!handler.StartObject()) - return false; - for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { - if (!handler.String(m->name.data_.s.str, m->name.data_.s.length, (m->name.flags_ & kCopyFlag) != 0)) - return false; - if (!m->value.Accept(handler)) - return false; - } - return handler.EndObject(data_.o.size); + case kObjectType: + if (!handler.StartObject()) + return false; + for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { + if (!handler.String(m->name.data_.s.str, m->name.data_.s.length, (m->name.flags_ & kCopyFlag) != 0)) + return false; + if (!m->value.Accept(handler)) + return false; + } + return handler.EndObject(data_.o.size); - case kArrayType: - if (!handler.StartArray()) - return false; - for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) - if (!v->Accept(handler)) - return false; - return handler.EndArray(data_.a.size); - - case kStringType: - return handler.String(data_.s.str, data_.s.length, (flags_ & kCopyFlag) != 0); - - case kNumberType: - if (IsInt()) return handler.Int(data_.n.i.i); - else if (IsUint()) return handler.Uint(data_.n.u.u); - else if (IsInt64()) return handler.Int64(data_.n.i64); - else if (IsUint64()) return handler.Uint64(data_.n.u64); - else return handler.Double(data_.n.d); - - default: - RAPIDJSON_ASSERT(false); - } - return false; - } + case kArrayType: + if (!handler.StartArray()) + return false; + for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) + if (!v->Accept(handler)) + return false; + return handler.EndArray(data_.a.size); + + case kStringType: + return handler.String(data_.s.str, data_.s.length, (flags_ & kCopyFlag) != 0); + + case kNumberType: + if (IsInt()) return handler.Int(data_.n.i.i); + else if (IsUint()) return handler.Uint(data_.n.u.u); + else if (IsInt64()) return handler.Int64(data_.n.i64); + else if (IsUint64()) return handler.Uint64(data_.n.u64); + else return handler.Double(data_.n.d); + + default: + RAPIDJSON_ASSERT(false); + } + return false; + } private: - template - friend class GenericDocument; + template + friend class GenericDocument; - enum { - kBoolFlag = 0x100, - kNumberFlag = 0x200, - kIntFlag = 0x400, - kUintFlag = 0x800, - kInt64Flag = 0x1000, - kUint64Flag = 0x2000, - kDoubleFlag = 0x4000, - kStringFlag = 0x100000, - kCopyFlag = 0x200000, + enum { + kBoolFlag = 0x100, + kNumberFlag = 0x200, + kIntFlag = 0x400, + kUintFlag = 0x800, + kInt64Flag = 0x1000, + kUint64Flag = 0x2000, + kDoubleFlag = 0x4000, + kStringFlag = 0x100000, + kCopyFlag = 0x200000, - // Initial flags of different types. - kNullFlag = kNullType, - kTrueFlag = kTrueType | kBoolFlag, - kFalseFlag = kFalseType | kBoolFlag, - kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, - kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, - kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, - kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, - kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, - kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, - kConstStringFlag = kStringType | kStringFlag, - kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, - kObjectFlag = kObjectType, - kArrayFlag = kArrayType, + // Initial flags of different types. + kNullFlag = kNullType, + kTrueFlag = kTrueType | kBoolFlag, + kFalseFlag = kFalseType | kBoolFlag, + kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, + kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, + kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, + kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, + kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, + kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, + kConstStringFlag = kStringType | kStringFlag, + kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, + kObjectFlag = kObjectType, + kArrayFlag = kArrayType, - kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler - }; + kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler + }; - static const SizeType kDefaultArrayCapacity = 16; - static const SizeType kDefaultObjectCapacity = 16; + static const SizeType kDefaultArrayCapacity = 16; + static const SizeType kDefaultObjectCapacity = 16; - struct String { - const Ch* str; - SizeType length; - unsigned hashcode; //!< reserved - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + struct String { + const Ch* str; + SizeType length; + unsigned hashcode; //!< reserved + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - // By using proper binary layout, retrieval of different integer types do not need conversions. - union Number { + // By using proper binary layout, retrieval of different integer types do not need conversions. + union Number { #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN - struct I { - int i; - char padding[4]; - }i; - struct U { - unsigned u; - char padding2[4]; - }u; + struct I { + int i; + char padding[4]; + }i; + struct U { + unsigned u; + char padding2[4]; + }u; #else - struct I { - char padding[4]; - int i; - }i; - struct U { - char padding2[4]; - unsigned u; - }u; + struct I { + char padding[4]; + int i; + }i; + struct U { + char padding2[4]; + unsigned u; + }u; #endif - int64_t i64; - uint64_t u64; - double d; - }; // 8 bytes + int64_t i64; + uint64_t u64; + double d; + }; // 8 bytes - struct Object { - Member* members; - SizeType size; - SizeType capacity; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + struct Object { + Member* members; + SizeType size; + SizeType capacity; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - struct Array { - GenericValue* elements; - SizeType size; - SizeType capacity; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + struct Array { + GenericValue* elements; + SizeType size; + SizeType capacity; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - union Data { - String s; - Number n; - Object o; - Array a; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + union Data { + String s; + Number n; + Object o; + Array a; + }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - // Initialize this value as array with initial data, without calling destructor. - void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { - flags_ = kArrayFlag; - data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); - memcpy(data_.a.elements, values, count * sizeof(GenericValue)); - data_.a.size = data_.a.capacity = count; - } + // Initialize this value as array with initial data, without calling destructor. + void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { + flags_ = kArrayFlag; + data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); + memcpy(data_.a.elements, values, count * sizeof(GenericValue)); + data_.a.size = data_.a.capacity = count; + } - //! Initialize this value as object with initial data, without calling destructor. - void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { - flags_ = kObjectFlag; - data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); - memcpy(data_.o.members, members, count * sizeof(Member)); - data_.o.size = data_.o.capacity = count; - } + //! Initialize this value as object with initial data, without calling destructor. + void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { + flags_ = kObjectFlag; + data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); + memcpy(data_.o.members, members, count * sizeof(Member)); + data_.o.size = data_.o.capacity = count; + } - //! Initialize this value as constant string, without calling destructor. - void SetStringRaw(StringRefType s) { - flags_ = kConstStringFlag; - data_.s.str = s; - data_.s.length = s.length; - } + //! Initialize this value as constant string, without calling destructor. + void SetStringRaw(StringRefType s) { + flags_ = kConstStringFlag; + data_.s.str = s; + data_.s.length = s.length; + } - //! Initialize this value as copy string with initial data, without calling destructor. - void SetStringRaw(StringRefType s, Allocator& allocator) { - flags_ = kCopyStringFlag; - data_.s.str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); - data_.s.length = s.length; - memcpy(const_cast(data_.s.str), s, s.length * sizeof(Ch)); - const_cast(data_.s.str)[s.length] = '\0'; - } + //! Initialize this value as copy string with initial data, without calling destructor. + void SetStringRaw(StringRefType s, Allocator& allocator) { + flags_ = kCopyStringFlag; + data_.s.str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); + data_.s.length = s.length; + memcpy(const_cast(data_.s.str), s, s.length * sizeof(Ch)); + const_cast(data_.s.str)[s.length] = '\0'; + } - //! Assignment without calling destructor - void RawAssign(GenericValue& rhs) { - data_ = rhs.data_; - flags_ = rhs.flags_; - rhs.flags_ = kNullFlag; - } + //! Assignment without calling destructor + void RawAssign(GenericValue& rhs) { + data_ = rhs.data_; + flags_ = rhs.flags_; + rhs.flags_ = kNullFlag; + } - bool StringEqual(const GenericValue& rhs) const { - RAPIDJSON_ASSERT(IsString()); - RAPIDJSON_ASSERT(rhs.IsString()); - return data_.s.length == rhs.data_.s.length && - (data_.s.str == rhs.data_.s.str // fast path for constant string - || memcmp(data_.s.str, rhs.data_.s.str, sizeof(Ch) * data_.s.length) == 0); - } + bool StringEqual(const GenericValue& rhs) const { + RAPIDJSON_ASSERT(IsString()); + RAPIDJSON_ASSERT(rhs.IsString()); + return data_.s.length == rhs.data_.s.length && + (data_.s.str == rhs.data_.s.str // fast path for constant string + || memcmp(data_.s.str, rhs.data_.s.str, sizeof(Ch) * data_.s.length) == 0); + } - Data data_; - unsigned flags_; + Data data_; + unsigned flags_; }; #pragma pack (pop) @@ -1385,218 +1405,218 @@ typedef GenericValue > Value; //! A document for parsing JSON text as DOM. /*! - \note implements Handler concept - \tparam Encoding encoding for both parsing and string storage. - \tparam Allocator allocator for allocating memory for the DOM, and the stack during parsing. - \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructors. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. + \note implements Handler concept + \tparam Encoding encoding for both parsing and string storage. + \tparam Allocator allocator for allocating memory for the DOM, and the stack during parsing. + \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructors. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. */ template > class GenericDocument : public GenericValue { public: - typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. - typedef GenericValue ValueType; //!< Value type of the document. - typedef Allocator AllocatorType; //!< Allocator type from template parameter. + typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. + typedef GenericValue ValueType; //!< Value type of the document. + typedef Allocator AllocatorType; //!< Allocator type from template parameter. - //! Constructor - /*! \param allocator Optional allocator for allocating stack memory. - \param stackCapacity Initial capacity of stack in bytes. - */ - GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {} + //! Constructor + /*! \param allocator Optional allocator for allocating stack memory. + \param stackCapacity Initial capacity of stack in bytes. + */ + GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {} - //!@name Parse from stream - //!@{ + //!@name Parse from stream + //!@{ - //! Parse JSON text from an input stream (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam SourceEncoding Encoding of input stream - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - ValueType::SetNull(); // Remove existing root if exist - GenericReader reader(&GetAllocator()); - ClearStackOnExit scope(*this); - parseResult_ = reader.template Parse(is, *this); - if (parseResult_) { - RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. - } - return *this; - } + //! Parse JSON text from an input stream (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam SourceEncoding Encoding of input stream + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + ValueType::SetNull(); // Remove existing root if exist + GenericReader reader(&GetAllocator()); + ClearStackOnExit scope(*this); + parseResult_ = reader.template Parse(is, *this); + if (parseResult_) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. + } + return *this; + } - //! Parse JSON text from an input stream - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } + //! Parse JSON text from an input stream + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } - //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \param is Input stream to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseStream(InputStream& is) { - return ParseStream(is); - } - //!@} + //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \param is Input stream to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream(is); + } + //!@} - //!@name Parse in-place from mutable string - //!@{ + //!@name Parse in-place from mutable string + //!@{ - //! Parse JSON text from a mutable string (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam SourceEncoding Transcoding from input Encoding - \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseInsitu(Ch* str) { - GenericInsituStringStream s(str); - return ParseStream(s); - } + //! Parse JSON text from a mutable string (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam SourceEncoding Transcoding from input Encoding + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + GenericInsituStringStream s(str); + return ParseStream(s); + } - //! Parse JSON text from a mutable string - /*! \tparam parseFlags Combination of \ref ParseFlag. - \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - template - GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); - } + //! Parse JSON text from a mutable string + /*! \tparam parseFlags Combination of \ref ParseFlag. + \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + template + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu(str); + } - //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) - /*! \param str Mutable zero-terminated string to be parsed. - \return The document itself for fluent API. - */ - GenericDocument& ParseInsitu(Ch* str) { - return ParseInsitu(str); - } - //!@} + //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) + /*! \param str Mutable zero-terminated string to be parsed. + \return The document itself for fluent API. + */ + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu(str); + } + //!@} - //!@name Parse from read-only string - //!@{ + //!@name Parse from read-only string + //!@{ - //! Parse JSON text from a read-only string (with Encoding conversion) - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \tparam SourceEncoding Transcoding from input Encoding - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const Ch* str) { - RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - GenericStringStream s(str); - return ParseStream(s); - } + //! Parse JSON text from a read-only string (with Encoding conversion) + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \tparam SourceEncoding Transcoding from input Encoding + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + GenericStringStream s(str); + return ParseStream(s); + } - //! Parse JSON text from a read-only string - /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). - \param str Read-only zero-terminated string to be parsed. - */ - template - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } + //! Parse JSON text from a read-only string + /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). + \param str Read-only zero-terminated string to be parsed. + */ + template + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } - //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) - /*! \param str Read-only zero-terminated string to be parsed. - */ - GenericDocument& Parse(const Ch* str) { - return Parse(str); - } - //!@} + //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) + /*! \param str Read-only zero-terminated string to be parsed. + */ + GenericDocument& Parse(const Ch* str) { + return Parse(str); + } + //!@} - //!@name Handling parse errors - //!@{ + //!@name Handling parse errors + //!@{ - //! Whether a parse error has occured in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } + //! Whether a parse error has occured in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseError() const { return parseResult_.Code(); } + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseError() const { return parseResult_.Code(); } - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } - //!@} + //!@} - //! Get the allocator of this document. - Allocator& GetAllocator() { return stack_.GetAllocator(); } + //! Get the allocator of this document. + Allocator& GetAllocator() { return stack_.GetAllocator(); } - //! Get the capacity of stack in bytes. - size_t GetStackCapacity() const { return stack_.GetCapacity(); } + //! Get the capacity of stack in bytes. + size_t GetStackCapacity() const { return stack_.GetCapacity(); } private: - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} - ~ClearStackOnExit() { d_.ClearStack(); } - private: - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - GenericDocument& d_; - }; + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} + ~ClearStackOnExit() { d_.ClearStack(); } + private: + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + GenericDocument& d_; + }; - // callers of the following private Handler functions - template friend class GenericReader; // for parsing - friend class GenericValue; // for deep copying + // callers of the following private Handler functions + template friend class GenericReader; // for parsing + friend class GenericValue; // for deep copying - // Implementation of Handler - bool Null() { new (stack_.template Push()) ValueType(); return true; } - bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } - bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } - bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } - bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } + // Implementation of Handler + bool Null() { new (stack_.template Push()) ValueType(); return true; } + bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } + bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } + bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } + bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } - bool String(const Ch* str, SizeType length, bool copy) { - if (copy) - new (stack_.template Push()) ValueType(str, length, GetAllocator()); - else - new (stack_.template Push()) ValueType(str, length); - return true; - } + bool String(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } - bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } - - bool EndObject(SizeType memberCount) { - typename ValueType::Member* members = stack_.template Pop(memberCount); - stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); - return true; - } + bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } + + bool EndObject(SizeType memberCount) { + typename ValueType::Member* members = stack_.template Pop(memberCount); + stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); + return true; + } - bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } - - bool EndArray(SizeType elementCount) { - ValueType* elements = stack_.template Pop(elementCount); - stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); - return true; - } + bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } + + bool EndArray(SizeType elementCount) { + ValueType* elements = stack_.template Pop(elementCount); + stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); + return true; + } private: - //! Prohibit assignment - GenericDocument& operator=(const GenericDocument&); + //! Prohibit assignment + GenericDocument& operator=(const GenericDocument&); - void ClearStack() { - if (Allocator::kNeedFree) - while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) - (stack_.template Pop(1))->~ValueType(); - else - stack_.Clear(); - } + void ClearStack() { + if (Allocator::kNeedFree) + while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) + (stack_.template Pop(1))->~ValueType(); + else + stack_.Clear(); + } - static const size_t kDefaultStackCapacity = 1024; - internal::Stack stack_; - ParseResult parseResult_; + static const size_t kDefaultStackCapacity = 1024; + internal::Stack stack_; + ParseResult parseResult_; }; //! GenericDocument with UTF8 encoding @@ -1608,9 +1628,9 @@ template inline GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) { - GenericDocument d(&allocator); - rhs.Accept(d); - RawAssign(*d.stack_.template Pop(1)); + GenericDocument d(&allocator); + rhs.Accept(d); + RawAssign(*d.stack_.template Pop(1)); } } // namespace rapidjson diff --git a/include/rapidjson/encodedstream.h b/include/rapidjson/encodedstream.h index 8345743..9dc00c7 100644 --- a/include/rapidjson/encodedstream.h +++ b/include/rapidjson/encodedstream.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_ @@ -12,251 +32,251 @@ namespace rapidjson { //! Input byte stream wrapper with a statically bound encoding. /*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam InputByteStream Type of input byte stream. For example, FileReadStream. + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileReadStream. */ template class EncodedInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - EncodedInputStream(InputByteStream& is) : is_(is) { - current_ = Encoding::TakeBOM(is_); - } + EncodedInputStream(InputByteStream& is) : is_(is) { + current_ = Encoding::TakeBOM(is_); + } - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } - size_t Tell() const { return is_.Tell(); } + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } + size_t Tell() const { return is_.Tell(); } - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: - EncodedInputStream(const EncodedInputStream&); - EncodedInputStream& operator=(const EncodedInputStream&); + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); - InputByteStream& is_; - Ch current_; + InputByteStream& is_; + Ch current_; }; //! Output byte stream wrapper with statically bound encoding. /*! - \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam InputByteStream Type of input byte stream. For example, FileWriteStream. + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. + \tparam InputByteStream Type of input byte stream. For example, FileWriteStream. */ template class EncodedOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { - if (putBOM) - Encoding::PutBOM(os_); - } + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { + if (putBOM) + Encoding::PutBOM(os_); + } - void Put(Ch c) { Encoding::Put(os_, c); } - void Flush() { os_.Flush(); } + void Put(Ch c) { Encoding::Put(os_, c); } + void Flush() { os_.Flush(); } - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); } - Ch Take() { RAPIDJSON_ASSERT(false); } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); } + Ch Take() { RAPIDJSON_ASSERT(false); } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: - EncodedOutputStream(const EncodedOutputStream&); - EncodedOutputStream& operator=(const EncodedOutputStream&); + EncodedOutputStream(const EncodedOutputStream&); + EncodedOutputStream& operator=(const EncodedOutputStream&); - OutputByteStream& os_; + OutputByteStream& os_; }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x //! Input stream wrapper with dynamically bound encoding and automatic encoding detection. /*! - \tparam CharType Type of character for reading. - \tparam InputByteStream type of input byte stream to be wrapped. + \tparam CharType Type of character for reading. + \tparam InputByteStream type of input byte stream to be wrapped. */ template class AutoUTFInputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: - typedef CharType Ch; + typedef CharType Ch; - //! Constructor. - /*! - \param is input stream to be wrapped. - \param type UTF encoding type if it is not detected from the stream. - */ - AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { - DetectType(); - static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; - takeFunc_ = f[type_]; - current_ = takeFunc_(*is_); - } + //! Constructor. + /*! + \param is input stream to be wrapped. + \param type UTF encoding type if it is not detected from the stream. + */ + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { + DetectType(); + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; + takeFunc_ = f[type_]; + current_ = takeFunc_(*is_); + } - UTFType GetType() const { return type_; } - bool HasBOM() const { return hasBOM_; } + UTFType GetType() const { return type_; } + bool HasBOM() const { return hasBOM_; } - Ch Peek() const { return current_; } - Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } - size_t Tell() const { return is_->Tell(); } + Ch Peek() const { return current_; } + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } + size_t Tell() const { return is_->Tell(); } - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: - AutoUTFInputStream(const AutoUTFInputStream&); - AutoUTFInputStream& operator=(const AutoUTFInputStream&); + AutoUTFInputStream(const AutoUTFInputStream&); + AutoUTFInputStream& operator=(const AutoUTFInputStream&); - // Detect encoding type with BOM or RFC 4627 - void DetectType() { - // BOM (Byte Order Mark): - // 00 00 FE FF UTF-32BE - // FF FE 00 00 UTF-32LE - // FE FF UTF-16BE - // FF FE UTF-16LE - // EF BB BF UTF-8 + // Detect encoding type with BOM or RFC 4627 + void DetectType() { + // BOM (Byte Order Mark): + // 00 00 FE FF UTF-32BE + // FF FE 00 00 UTF-32LE + // FE FF UTF-16BE + // FF FE UTF-16LE + // EF BB BF UTF-8 - const unsigned char* c = (const unsigned char *)is_->Peek4(); - if (!c) - return; + const unsigned char* c = (const unsigned char *)is_->Peek4(); + if (!c) + return; - unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); - hasBOM_ = false; - if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } - else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } + unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); + hasBOM_ = false; + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } - // RFC 4627: Section 3 - // "Since the first two characters of a JSON text will always be ASCII - // characters [RFC0020], it is possible to determine whether an octet - // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking - // at the pattern of nulls in the first four octets." - // 00 00 00 xx UTF-32BE - // 00 xx 00 xx UTF-16BE - // xx 00 00 00 UTF-32LE - // xx 00 xx 00 UTF-16LE - // xx xx xx xx UTF-8 + // RFC 4627: Section 3 + // "Since the first two characters of a JSON text will always be ASCII + // characters [RFC0020], it is possible to determine whether an octet + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking + // at the pattern of nulls in the first four octets." + // 00 00 00 xx UTF-32BE + // 00 xx 00 xx UTF-16BE + // xx 00 00 00 UTF-32LE + // xx 00 xx 00 UTF-16LE + // xx xx xx xx UTF-8 - if (!hasBOM_) { - unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); - switch (pattern) { - case 0x08: type_ = kUTF32BE; break; - case 0x0A: type_ = kUTF16BE; break; - case 0x01: type_ = kUTF32LE; break; - case 0x05: type_ = kUTF16LE; break; - case 0x0F: type_ = kUTF8; break; - default: break; // Use type defined by user. - } - } + if (!hasBOM_) { + unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + switch (pattern) { + case 0x08: type_ = kUTF32BE; break; + case 0x0A: type_ = kUTF16BE; break; + case 0x01: type_ = kUTF32LE; break; + case 0x05: type_ = kUTF16LE; break; + case 0x0F: type_ = kUTF8; break; + default: break; // Use type defined by user. + } + } - // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. - switch (type_) { - case kUTF8: - // Do nothing - break; - case kUTF16LE: - case kUTF16BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - break; - case kUTF32LE: - case kUTF32BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - break; - default: - RAPIDJSON_ASSERT(false); // Invalid type - } - } + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. + switch (type_) { + case kUTF8: + // Do nothing + break; + case kUTF16LE: + case kUTF16BE: + RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + break; + case kUTF32LE: + case kUTF32BE: + RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + break; + default: + RAPIDJSON_ASSERT(false); // Invalid type + } + } - typedef Ch (*TakeFunc)(InputByteStream& is); - InputByteStream* is_; - UTFType type_; - Ch current_; - TakeFunc takeFunc_; - bool hasBOM_; + typedef Ch (*TakeFunc)(InputByteStream& is); + InputByteStream* is_; + UTFType type_; + Ch current_; + TakeFunc takeFunc_; + bool hasBOM_; }; //! Output stream wrapper with dynamically bound encoding and automatic encoding detection. /*! - \tparam CharType Type of character for writing. - \tparam InputByteStream type of output byte stream to be wrapped. + \tparam CharType Type of character for writing. + \tparam InputByteStream type of output byte stream to be wrapped. */ template class AutoUTFOutputStream { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: - typedef CharType Ch; + typedef CharType Ch; - //! Constructor. - /*! - \param os output stream to be wrapped. - \param type UTF encoding type. - \param putBOM Whether to write BOM at the beginning of the stream. - */ - AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { - // RUntime check whether the size of character type is sufficient. It only perform checks with assertion. - switch (type_) { - case kUTF16LE: - case kUTF16BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 2); - break; - case kUTF32LE: - case kUTF32BE: - RAPIDJSON_ASSERT(sizeof(Ch) >= 4); - break; - case kUTF8: - // Do nothing - break; - default: - RAPIDJSON_ASSERT(false); // Invalid UTFType - } + //! Constructor. + /*! + \param os output stream to be wrapped. + \param type UTF encoding type. + \param putBOM Whether to write BOM at the beginning of the stream. + */ + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { + // RUntime check whether the size of character type is sufficient. It only perform checks with assertion. + switch (type_) { + case kUTF16LE: + case kUTF16BE: + RAPIDJSON_ASSERT(sizeof(Ch) >= 2); + break; + case kUTF32LE: + case kUTF32BE: + RAPIDJSON_ASSERT(sizeof(Ch) >= 4); + break; + case kUTF8: + // Do nothing + break; + default: + RAPIDJSON_ASSERT(false); // Invalid UTFType + } - static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; - putFunc_ = f[type_]; + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; + putFunc_ = f[type_]; - if (putBOM) - PutBOM(); - } + if (putBOM) + PutBOM(); + } - UTFType GetType() const { return type_; } + UTFType GetType() const { return type_; } - void Put(Ch c) { putFunc_(*os_, c); } - void Flush() { os_->Flush(); } + void Put(Ch c) { putFunc_(*os_, c); } + void Flush() { os_->Flush(); } - // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); } - Ch Take() { RAPIDJSON_ASSERT(false); } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + // Not implemented + Ch Peek() const { RAPIDJSON_ASSERT(false); } + Ch Take() { RAPIDJSON_ASSERT(false); } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: - AutoUTFOutputStream(const AutoUTFOutputStream&); - AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); + AutoUTFOutputStream(const AutoUTFOutputStream&); + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); - void PutBOM() { - typedef void (*PutBOMFunc)(OutputByteStream&); - static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; - f[type_](*os_); - } + void PutBOM() { + typedef void (*PutBOMFunc)(OutputByteStream&); + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; + f[type_](*os_); + } - typedef void (*PutFunc)(OutputByteStream&, Ch); + typedef void (*PutFunc)(OutputByteStream&, Ch); - OutputByteStream* os_; - UTFType type_; - PutFunc putFunc_; + OutputByteStream* os_; + UTFType type_; + PutFunc putFunc_; }; #undef RAPIDJSON_ENCODINGS_FUNC diff --git a/include/rapidjson/encodings.h b/include/rapidjson/encodings.h index 2861362..5c7da3e 100644 --- a/include/rapidjson/encodings.h +++ b/include/rapidjson/encodings.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_ENCODINGS_H_ #define RAPIDJSON_ENCODINGS_H_ @@ -18,52 +38,52 @@ namespace rapidjson { // Encoding /*! \class rapidjson::Encoding - \brief Concept for encoding of Unicode characters. + \brief Concept for encoding of Unicode characters. \code concept Encoding { - typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. - enum { supportUnicode = 1 }; // or 0 if not supporting unicode + enum { supportUnicode = 1 }; // or 0 if not supporting unicode - //! \brief Encode a Unicode codepoint to an output stream. - //! \param os Output stream. - //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. - template - static void Encode(OutputStream& os, unsigned codepoint); + //! \brief Encode a Unicode codepoint to an output stream. + //! \param os Output stream. + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. + template + static void Encode(OutputStream& os, unsigned codepoint); - //! \brief Decode a Unicode codepoint from an input stream. - //! \param is Input stream. - //! \param codepoint Output of the unicode codepoint. - //! \return true if a valid codepoint can be decoded from the stream. - template - static bool Decode(InputStream& is, unsigned* codepoint); + //! \brief Decode a Unicode codepoint from an input stream. + //! \param is Input stream. + //! \param codepoint Output of the unicode codepoint. + //! \return true if a valid codepoint can be decoded from the stream. + template + static bool Decode(InputStream& is, unsigned* codepoint); - //! \brief Validate one Unicode codepoint from an encoded stream. - //! \param is Input stream to obtain codepoint. - //! \param os Output for copying one codepoint. - //! \return true if it is valid. - //! \note This function just validating and copying the codepoint without actually decode it. - template - static bool Validate(InputStream& is, OutputStream& os); + //! \brief Validate one Unicode codepoint from an encoded stream. + //! \param is Input stream to obtain codepoint. + //! \param os Output for copying one codepoint. + //! \return true if it is valid. + //! \note This function just validating and copying the codepoint without actually decode it. + template + static bool Validate(InputStream& is, OutputStream& os); - // The following functions are deal with byte streams. + // The following functions are deal with byte streams. - //! Take a character from input byte stream, skip BOM if exist. - template - static CharType TakeBOM(InputByteStream& is); + //! Take a character from input byte stream, skip BOM if exist. + template + static CharType TakeBOM(InputByteStream& is); - //! Take a character from input byte stream. - template - static Ch Take(InputByteStream& is); + //! Take a character from input byte stream. + template + static Ch Take(InputByteStream& is); - //! Put BOM to output byte stream. - template - static void PutBOM(OutputByteStream& os); + //! Put BOM to output byte stream. + template + static void PutBOM(OutputByteStream& os); - //! Put a character to output byte stream. - template - static void Put(OutputByteStream& os, Ch c); + //! Put a character to output byte stream. + template + static void Put(OutputByteStream& os, Ch c); }; \endcode */ @@ -73,141 +93,141 @@ concept Encoding { //! UTF-8 encoding. /*! http://en.wikipedia.org/wiki/UTF-8 - http://tools.ietf.org/html/rfc3629 - \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. - \note implements Encoding concept + http://tools.ietf.org/html/rfc3629 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. + \note implements Encoding concept */ template struct UTF8 { - typedef CharType Ch; + typedef CharType Ch; - enum { supportUnicode = 1 }; + enum { supportUnicode = 1 }; - template - static void Encode(OutputStream& os, unsigned codepoint) { - if (codepoint <= 0x7F) - os.Put(static_cast(codepoint & 0xFF)); - else if (codepoint <= 0x7FF) { - os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); - } - else if (codepoint <= 0xFFFF) { - os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); - os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - os.Put(static_cast(0x80 | (codepoint & 0x3F))); - } - } + template + static void Encode(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + os.Put(static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + os.Put(static_cast(0x80 | (codepoint & 0x3F))); + } + } - template - static bool Decode(InputStream& is, unsigned* codepoint) { + template + static bool Decode(InputStream& is, unsigned* codepoint) { #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) - Ch c = is.Take(); - if (!(c & 0x80)) { - *codepoint = (unsigned char)c; - return true; - } + Ch c = is.Take(); + if (!(c & 0x80)) { + *codepoint = (unsigned char)c; + return true; + } - unsigned char type = GetRange((unsigned char)c); - *codepoint = (0xFF >> type) & (unsigned char)c; - bool result = true; - switch (type) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; - default: return false; - } + unsigned char type = GetRange((unsigned char)c); + *codepoint = (0xFF >> type) & (unsigned char)c; + bool result = true; + switch (type) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } #undef COPY #undef TRANS #undef TAIL - } + } - template - static bool Validate(InputStream& is, OutputStream& os) { + template + static bool Validate(InputStream& is, OutputStream& os) { #define COPY() os.Put(c = is.Take()) #define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) - Ch c; - COPY(); - if (!(c & 0x80)) - return true; + Ch c; + COPY(); + if (!(c & 0x80)) + return true; - bool result = true; - switch (GetRange((unsigned char)c)) { - case 2: TAIL(); return result; - case 3: TAIL(); TAIL(); return result; - case 4: COPY(); TRANS(0x50); TAIL(); return result; - case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; - case 6: TAIL(); TAIL(); TAIL(); return result; - case 10: COPY(); TRANS(0x20); TAIL(); return result; - case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; - default: return false; - } + bool result = true; + switch (GetRange((unsigned char)c)) { + case 2: TAIL(); return result; + case 3: TAIL(); TAIL(); return result; + case 4: COPY(); TRANS(0x50); TAIL(); return result; + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; + case 6: TAIL(); TAIL(); TAIL(); return result; + case 10: COPY(); TRANS(0x20); TAIL(); return result; + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; + default: return false; + } #undef COPY #undef TRANS #undef TAIL - } + } - static unsigned char GetRange(unsigned char c) { - // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ - // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. - static const unsigned char type[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, - 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - }; - return type[c]; - } + static unsigned char GetRange(unsigned char c) { + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. + static const unsigned char type[] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + }; + return type[c]; + } - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - Ch c = Take(is); - if ((unsigned char)c != 0xEFu) return c; - c = is.Take(); - if ((unsigned char)c != 0xBBu) return c; - c = is.Take(); - if ((unsigned char)c != 0xBFu) return c; - c = is.Take(); - return c; - } + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + Ch c = Take(is); + if ((unsigned char)c != 0xEFu) return c; + c = is.Take(); + if ((unsigned char)c != 0xBBu) return c; + c = is.Take(); + if ((unsigned char)c != 0xBFu) return c; + c = is.Take(); + return c; + } - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return is.Take(); - } + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return is.Take(); + } - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); - } + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); + } - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -215,131 +235,131 @@ struct UTF8 { //! UTF-16 encoding. /*! http://en.wikipedia.org/wiki/UTF-16 - http://tools.ietf.org/html/rfc2781 - \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. - \note implements Encoding concept + http://tools.ietf.org/html/rfc2781 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. + \note implements Encoding concept - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF16LE and UTF16BE, which handle endianness. + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF16LE and UTF16BE, which handle endianness. */ template struct UTF16 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); - enum { supportUnicode = 1 }; + enum { supportUnicode = 1 }; - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - if (codepoint <= 0xFFFF) { - RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair - os.Put(static_cast(codepoint)); - } - else { - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - unsigned v = codepoint - 0x10000; - os.Put(static_cast((v >> 10) | 0xD800)); - os.Put((v & 0x3FF) | 0xDC00); - } - } + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + os.Put(static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + os.Put(static_cast((v >> 10) | 0xD800)); + os.Put((v & 0x3FF) | 0xDC00); + } + } - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - Ch c = is.Take(); - if (c < 0xD800 || c > 0xDFFF) { - *codepoint = c; - return true; - } - else if (c <= 0xDBFF) { - *codepoint = (c & 0x3FF) << 10; - c = is.Take(); - *codepoint |= (c & 0x3FF); - *codepoint += 0x10000; - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + Ch c = is.Take(); + if (c < 0xD800 || c > 0xDFFF) { + *codepoint = c; + return true; + } + else if (c <= 0xDBFF) { + *codepoint = (c & 0x3FF) << 10; + c = is.Take(); + *codepoint |= (c & 0x3FF); + *codepoint += 0x10000; + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - Ch c; - os.Put(c = is.Take()); - if (c < 0xD800 || c > 0xDFFF) - return true; - else if (c <= 0xDBFF) { - os.Put(c = is.Take()); - return c >= 0xDC00 && c <= 0xDFFF; - } - return false; - } + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + Ch c; + os.Put(c = is.Take()); + if (c < 0xD800 || c > 0xDFFF) + return true; + else if (c <= 0xDBFF) { + os.Put(c = is.Take()); + return c >= 0xDC00 && c <= 0xDFFF; + } + return false; + } }; //! UTF-16 little endian encoding. template struct UTF16LE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return (unsigned short)c == 0xFEFFu ? Take(is) : c; - } + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned short)c == 0xFEFFu ? Take(is) : c; + } - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take(); - c |= (unsigned char)is.Take() << 8; - return c; - } + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take(); + c |= (unsigned char)is.Take() << 8; + return c; + } - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFFu); os.Put(0xFEu); - } + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xFFu); os.Put(0xFEu); + } - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(c & 0xFFu); - os.Put((c >> 8) & 0xFFu); - } + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(c & 0xFFu); + os.Put((c >> 8) & 0xFFu); + } }; //! UTF-16 big endian encoding. template struct UTF16BE : UTF16 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return (unsigned short)c == 0xFEFFu ? Take(is) : c; - } + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned short)c == 0xFEFFu ? Take(is) : c; + } - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take(); - return c; - } + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take() << 8; + c |= (unsigned char)is.Take(); + return c; + } - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFEu); os.Put(0xFFu); - } + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xFEu); os.Put(0xFFu); + } - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put((c >> 8) & 0xFFu); - os.Put(c & 0xFFu); - } + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put((c >> 8) & 0xFFu); + os.Put(c & 0xFFu); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -347,113 +367,113 @@ struct UTF16BE : UTF16 { //! UTF-32 encoding. /*! http://en.wikipedia.org/wiki/UTF-32 - \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. - \note implements Encoding concept + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. + \note implements Encoding concept - \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. - For streaming, use UTF32LE and UTF32BE, which handle endianness. + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. + For streaming, use UTF32LE and UTF32BE, which handle endianness. */ template struct UTF32 { - typedef CharType Ch; - RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); + typedef CharType Ch; + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); - enum { supportUnicode = 1 }; + enum { supportUnicode = 1 }; - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); - RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); - os.Put(codepoint); - } + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + os.Put(codepoint); + } - template - static bool Decode(InputStream& is, unsigned* codepoint) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c = is.Take(); - *codepoint = c; - return c <= 0x10FFFF; - } + template + static bool Decode(InputStream& is, unsigned* codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c = is.Take(); + *codepoint = c; + return c <= 0x10FFFF; + } - template - static bool Validate(InputStream& is, OutputStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); - Ch c; - os.Put(c = is.Take()); - return c <= 0x10FFFF; - } + template + static bool Validate(InputStream& is, OutputStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); + Ch c; + os.Put(c = is.Take()); + return c <= 0x10FFFF; + } }; //! UTF-32 little endian enocoding. template struct UTF32LE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return (unsigned)c == 0x0000FEFFu ? Take(is) : c; - } + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + } - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take(); - c |= (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take() << 16; - c |= (unsigned char)is.Take() << 24; - return c; - } + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take(); + c |= (unsigned char)is.Take() << 8; + c |= (unsigned char)is.Take() << 16; + c |= (unsigned char)is.Take() << 24; + return c; + } - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); - } + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); + } - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(c & 0xFFu); - os.Put((c >> 8) & 0xFFu); - os.Put((c >> 16) & 0xFFu); - os.Put((c >> 24) & 0xFFu); - } + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(c & 0xFFu); + os.Put((c >> 8) & 0xFFu); + os.Put((c >> 16) & 0xFFu); + os.Put((c >> 24) & 0xFFu); + } }; //! UTF-32 big endian encoding. template struct UTF32BE : UTF32 { - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = Take(is); - return (unsigned)c == 0x0000FEFFu ? Take(is) : c; - } + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = Take(is); + return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + } - template - static CharType Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take() << 24; - c |= (unsigned char)is.Take() << 16; - c |= (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take(); - return c; - } + template + static CharType Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + CharType c = (unsigned char)is.Take() << 24; + c |= (unsigned char)is.Take() << 16; + c |= (unsigned char)is.Take() << 8; + c |= (unsigned char)is.Take(); + return c; + } - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); - } + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); + } - template - static void Put(OutputByteStream& os, CharType c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put((c >> 24) & 0xFFu); - os.Put((c >> 16) & 0xFFu); - os.Put((c >> 8) & 0xFFu); - os.Put(c & 0xFFu); - } + template + static void Put(OutputByteStream& os, CharType c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put((c >> 24) & 0xFFu); + os.Put((c >> 16) & 0xFFu); + os.Put((c >> 8) & 0xFFu); + os.Put(c & 0xFFu); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -461,59 +481,59 @@ struct UTF32BE : UTF32 { //! ASCII encoding. /*! http://en.wikipedia.org/wiki/ASCII - \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. - \note implements Encoding concept + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. + \note implements Encoding concept */ template struct ASCII { - typedef CharType Ch; + typedef CharType Ch; - enum { supportUnicode = 0 }; + enum { supportUnicode = 0 }; - template - static void Encode(OutputStream& os, unsigned codepoint) { - RAPIDJSON_ASSERT(codepoint <= 0x7F); - os.Put(static_cast(codepoint & 0xFF)); - } + template + static void Encode(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + os.Put(static_cast(codepoint & 0xFF)); + } - template - static bool Decode(InputStream& is, unsigned* codepoint) { - unsigned char c = static_cast(is.Take()); - *codepoint = c; - return c <= 0X7F; - } + template + static bool Decode(InputStream& is, unsigned* codepoint) { + unsigned char c = static_cast(is.Take()); + *codepoint = c; + return c <= 0X7F; + } - template - static bool Validate(InputStream& is, OutputStream& os) { - unsigned char c = is.Take(); - os.Put(c); - return c <= 0x7F; - } + template + static bool Validate(InputStream& is, OutputStream& os) { + unsigned char c = is.Take(); + os.Put(c); + return c <= 0x7F; + } - template - static CharType TakeBOM(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - Ch c = Take(is); - return c; - } + template + static CharType TakeBOM(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + Ch c = Take(is); + return c; + } - template - static Ch Take(InputByteStream& is) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return is.Take(); - } + template + static Ch Take(InputByteStream& is) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); + return is.Take(); + } - template - static void PutBOM(OutputByteStream& os) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - (void)os; - } + template + static void PutBOM(OutputByteStream& os) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + (void)os; + } - template - static void Put(OutputByteStream& os, Ch c) { - RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(static_cast(c)); - } + template + static void Put(OutputByteStream& os, Ch c) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); + os.Put(static_cast(c)); + } }; /////////////////////////////////////////////////////////////////////////////// @@ -521,11 +541,11 @@ struct ASCII { //! Runtime-specified UTF encoding type of a stream. enum UTFType { - kUTF8 = 0, //!< UTF-8. - kUTF16LE = 1, //!< UTF-16 little endian. - kUTF16BE = 2, //!< UTF-16 big endian. - kUTF32LE = 3, //!< UTF-32 little endian. - kUTF32BE = 4 //!< UTF-32 big endian. + kUTF8 = 0, //!< UTF-8. + kUTF16LE = 1, //!< UTF-16 little endian. + kUTF16BE = 2, //!< UTF-16 big endian. + kUTF32LE = 3, //!< UTF-32 little endian. + kUTF32BE = 4 //!< UTF-32 big endian. }; //! Dynamically select encoding according to stream's runtime-specified UTF encoding type. @@ -533,32 +553,32 @@ enum UTFType { */ template struct AutoUTF { - typedef CharType Ch; + typedef CharType Ch; - enum { supportUnicode = 1 }; + enum { supportUnicode = 1 }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x - template - RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { - typedef void (*EncodeFunc)(OutputStream&, unsigned); - static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; - (*f[os.GetType()])(os, codepoint); - } + template + RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; + (*f[os.GetType()])(os, codepoint); + } - template - RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { - typedef bool (*DecodeFunc)(InputStream&, unsigned*); - static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; - return (*f[is.GetType()])(is, codepoint); - } + template + RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + typedef bool (*DecodeFunc)(InputStream&, unsigned*); + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; + return (*f[is.GetType()])(is, codepoint); + } - template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { - typedef bool (*ValidateFunc)(InputStream&, OutputStream&); - static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; - return (*f[is.GetType()])(is, os); - } + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + typedef bool (*ValidateFunc)(InputStream&, OutputStream&); + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; + return (*f[is.GetType()])(is, os); + } #undef RAPIDJSON_ENCODINGS_FUNC }; @@ -569,36 +589,36 @@ struct AutoUTF { //! Encoding conversion. template struct Transcoder { - //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. - template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - TargetEncoding::Encode(os, codepoint); - return true; - } + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. + template + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::Encode(os, codepoint); + return true; + } - //! Validate one Unicode codepoint from an encoded stream. - template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { - return Transcode(is, os); // Since source/target encoding is different, must transcode. - } + //! Validate one Unicode codepoint from an encoded stream. + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + return Transcode(is, os); // Since source/target encoding is different, must transcode. + } }; //! Specialization of Transcoder with same source and target encoding. template struct Transcoder { - template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { - os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. - return true; - } - - template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { - return Encoding::Validate(is, os); // source/target encoding are the same - } + template + RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + return Encoding::Validate(is, os); // source/target encoding are the same + } }; } // namespace rapidjson diff --git a/include/rapidjson/error/en.h b/include/rapidjson/error/en.h index e9120c5..b4a3ae1 100644 --- a/include/rapidjson/error/en.h +++ b/include/rapidjson/error/en.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_ERROR_EN_H__ #define RAPIDJSON_ERROR_EN_H__ @@ -7,43 +27,43 @@ namespace rapidjson { //! Maps error code of parsing into error message. /*! - \param parseErrorCode Error code obtained in parsing. - \return the error message. - \note User can make a copy of this function for localization. - Using switch-case is safer for future modification of error codes. + \param parseErrorCode Error code obtained in parsing. + \return the error message. + \note User can make a copy of this function for localization. + Using switch-case is safer for future modification of error codes. */ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { - switch (parseErrorCode) { - case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); + switch (parseErrorCode) { + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); - case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); - case kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array."); - case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); - - case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); - - case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); - case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); - case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); - - case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); + case kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array."); + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); + + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); + + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); + + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); - case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); - case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); - case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); - case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); - case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); - case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); - case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); - case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); - case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); - case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - default: - return RAPIDJSON_ERROR_STRING("Unknown error."); - } + default: + return RAPIDJSON_ERROR_STRING("Unknown error."); + } } } // namespace rapidjson diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h index 981cbd9..bc5462a 100644 --- a/include/rapidjson/error/error.h +++ b/include/rapidjson/error/error.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_ERROR_ERROR_H__ #define RAPIDJSON_ERROR_ERROR_H__ @@ -6,8 +26,8 @@ //! Character type of error messages. /*! The default charater type is char. - On Windows, user can define this macro as TCHAR for supporting both - unicode/non-unicode settings. + On Windows, user can define this macro as TCHAR for supporting both + unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_CHARTYPE #define RAPIDJSON_ERROR_CHARTYPE char @@ -18,8 +38,8 @@ //! Macro for converting string literial to RAPIDJSON_ERROR_CHARTYPE[]. /*! By default this conversion macro does nothing. - On Windows, user can define this macro as _T(x) for supporting both - unicode/non-unicode settings. + On Windows, user can define this macro as _T(x) for supporting both + unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_STRING #define RAPIDJSON_ERROR_STRING(x) x @@ -34,85 +54,85 @@ namespace rapidjson { /*! \see GenericReader::Parse, GenericReader::GetParseErrorCode */ enum ParseErrorCode { - kParseErrorNone = 0, //!< No error. + kParseErrorNone = 0, //!< No error. - kParseErrorDocumentEmpty, //!< The document is empty. - kParseErrorDocumentRootNotObjectOrArray, //!< The document root must be either object or array. - kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. + kParseErrorDocumentEmpty, //!< The document is empty. + kParseErrorDocumentRootNotObjectOrArray, //!< The document root must be either object or array. + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. - kParseErrorValueInvalid, //!< Invalid value. + kParseErrorValueInvalid, //!< Invalid value. - kParseErrorObjectMissName, //!< Missing a name for object member. - kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. - kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. + kParseErrorObjectMissName, //!< Missing a name for object member. + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. - kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. - kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. - kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. - kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. - kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. - kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. - kParseErrorNumberTooBig, //!< Number too big to be stored in double. - kParseErrorNumberMissFraction, //!< Miss fraction part in number. - kParseErrorNumberMissExponent, //!< Miss exponent in number. + kParseErrorNumberTooBig, //!< Number too big to be stored in double. + kParseErrorNumberMissFraction, //!< Miss fraction part in number. + kParseErrorNumberMissExponent, //!< Miss exponent in number. - kParseErrorTermination, //!< Parsing was terminated. - kParseErrorUnspecificSyntaxError, //!< Unspecific syntax error. + kParseErrorTermination, //!< Parsing was terminated. + kParseErrorUnspecificSyntaxError, //!< Unspecific syntax error. }; //! Result of parsing (wraps ParseErrorCode) /*! - \code - Document doc; - ParseResult ok = doc.Parse("[42]"); - if (!ok) { - fprintf(stderr, "JSON parse error: %s (%u)", - GetParseError_En(ok.Code()), ok.Offset()); - exit(EXIT_FAILURE); - } - \endcode - \see GenericReader::Parse, GenericDocument::Parse + \code + Document doc; + ParseResult ok = doc.Parse("[42]"); + if (!ok) { + fprintf(stderr, "JSON parse error: %s (%u)", + GetParseError_En(ok.Code()), ok.Offset()); + exit(EXIT_FAILURE); + } + \endcode + \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { - //! Default constructor, no error. - ParseResult() : code_(kParseErrorNone), offset_(0) {} - //! Constructor to set an error. - ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} + //! Default constructor, no error. + ParseResult() : code_(kParseErrorNone), offset_(0) {} + //! Constructor to set an error. + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} - //! Get the error code. - ParseErrorCode Code() const { return code_; } - //! Get the error offset, if \ref IsError(), 0 otherwise. - size_t Offset() const { return offset_; } + //! Get the error code. + ParseErrorCode Code() const { return code_; } + //! Get the error offset, if \ref IsError(), 0 otherwise. + size_t Offset() const { return offset_; } - //! Conversion to \c bool, returns \c true, iff !\ref IsError(). - operator bool() const { return !IsError(); } - //! Whether the result is an error. - bool IsError() const { return code_ != kParseErrorNone; } + //! Conversion to \c bool, returns \c true, iff !\ref IsError(). + operator bool() const { return !IsError(); } + //! Whether the result is an error. + bool IsError() const { return code_ != kParseErrorNone; } - bool operator==(const ParseResult& that) const { return code_ == that.code_; } - bool operator==(ParseErrorCode code) const { return code_ == code; } - friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + bool operator==(const ParseResult& that) const { return code_ == that.code_; } + bool operator==(ParseErrorCode code) const { return code_ == code; } + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } - //! Reset error code. - void Clear() { Set(kParseErrorNone); } - //! Update error code and offset. - void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } + //! Reset error code. + void Clear() { Set(kParseErrorNone); } + //! Update error code and offset. + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } private: - ParseErrorCode code_; - size_t offset_; + ParseErrorCode code_; + size_t offset_; }; //! Function pointer type of GetParseError(). /*! This is the prototype for GetParseError_X(), where X is a locale. - User can dynamically change locale in runtime, e.g.: + User can dynamically change locale in runtime, e.g.: \code - GetParseErrorFunc GetParseError = GetParseError_En; // or whatever - const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); \endcode */ diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index 4d42d38..31c193b 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_ @@ -8,65 +28,65 @@ namespace rapidjson { //! File byte stream for input using fread(). /*! - \note implements Stream concept + \note implements Stream concept */ class FileReadStream { public: - typedef char Ch; //!< Character type (byte). + typedef char Ch; //!< Character type (byte). - //! Constructor. - /*! - \param fp File pointer opened for read. - \param buffer user-supplied buffer. - \param bufferSize size of buffer in bytes. Must >=4 bytes. - */ - FileReadStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { - RAPIDJSON_ASSERT(fp_ != 0); - RAPIDJSON_ASSERT(bufferSize >= 4); - Read(); - } + //! Constructor. + /*! + \param fp File pointer opened for read. + \param buffer user-supplied buffer. + \param bufferSize size of buffer in bytes. Must >=4 bytes. + */ + FileReadStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { + RAPIDJSON_ASSERT(fp_ != 0); + RAPIDJSON_ASSERT(bufferSize >= 4); + Read(); + } - Ch Peek() const { return *current_; } - Ch Take() { Ch c = *current_; Read(); return c; } - size_t Tell() const { return count_ + static_cast(current_ - buffer_); } + Ch Peek() const { return *current_; } + Ch Take() { Ch c = *current_; Read(); return c; } + size_t Tell() const { return count_ + static_cast(current_ - buffer_); } - // Not implemented - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + // Not implemented + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - // For encoding detection only. - const Ch* Peek4() const { - return (current_ + 4 <= bufferLast_) ? current_ : 0; - } + // For encoding detection only. + const Ch* Peek4() const { + return (current_ + 4 <= bufferLast_) ? current_ : 0; + } private: - void Read() { - if (current_ < bufferLast_) - ++current_; - else if (!eof_) { - count_ += readCount_; - readCount_ = fread(buffer_, 1, bufferSize_, fp_); - bufferLast_ = buffer_ + readCount_ - 1; - current_ = buffer_; + void Read() { + if (current_ < bufferLast_) + ++current_; + else if (!eof_) { + count_ += readCount_; + readCount_ = fread(buffer_, 1, bufferSize_, fp_); + bufferLast_ = buffer_ + readCount_ - 1; + current_ = buffer_; - if (readCount_ < bufferSize_) { - buffer_[readCount_] = '\0'; - ++bufferLast_; - eof_ = true; - } - } - } + if (readCount_ < bufferSize_) { + buffer_[readCount_] = '\0'; + ++bufferLast_; + eof_ = true; + } + } + } - FILE* fp_; - Ch *buffer_; - size_t bufferSize_; - Ch *bufferLast_; - Ch *current_; - size_t readCount_; - size_t count_; //!< Number of characters read - bool eof_; + FILE* fp_; + Ch *buffer_; + size_t bufferSize_; + Ch *bufferLast_; + Ch *current_; + size_t readCount_; + size_t count_; //!< Number of characters read + bool eof_; }; } // namespace rapidjson diff --git a/include/rapidjson/filestream.h b/include/rapidjson/filestream.h index 7e1e3b1..6995b3d 100644 --- a/include/rapidjson/filestream.h +++ b/include/rapidjson/filestream.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_FILESTREAM_H_ #define RAPIDJSON_FILESTREAM_H_ @@ -8,44 +28,44 @@ namespace rapidjson { //! (Depreciated) Wrapper of C file stream for input or output. /*! - This simple wrapper does not check the validity of the stream. - \note implements Stream concept - \note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead. + This simple wrapper does not check the validity of the stream. + \note implements Stream concept + \note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead. */ class FileStream { public: - typedef char Ch; //!< Character type. Only support char. + typedef char Ch; //!< Character type. Only support char. - FileStream(FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); } - char Peek() const { return current_; } - char Take() { char c = current_; Read(); return c; } - size_t Tell() const { return count_; } - void Put(char c) { fputc(c, fp_); } - void Flush() { fflush(fp_); } + FileStream(FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); } + char Peek() const { return current_; } + char Take() { char c = current_; Read(); return c; } + size_t Tell() const { return count_; } + void Put(char c) { fputc(c, fp_); } + void Flush() { fflush(fp_); } - // Not implemented - char* PutBegin() { return 0; } - size_t PutEnd(char*) { return 0; } + // Not implemented + char* PutBegin() { return 0; } + size_t PutEnd(char*) { return 0; } private: - // Prohibit copy constructor & assignment operator. - FileStream(const FileStream&); - FileStream& operator=(const FileStream&); + // Prohibit copy constructor & assignment operator. + FileStream(const FileStream&); + FileStream& operator=(const FileStream&); - void Read() { - RAPIDJSON_ASSERT(fp_ != 0); - int c = fgetc(fp_); - if (c != EOF) { - current_ = (char)c; - count_++; - } - else if (current_ != '\0') - current_ = '\0'; - } + void Read() { + RAPIDJSON_ASSERT(fp_ != 0); + int c = fgetc(fp_); + if (c != EOF) { + current_ = (char)c; + count_++; + } + else if (current_ != '\0') + current_ = '\0'; + } - FILE* fp_; - char current_; - size_t count_; + FILE* fp_; + char current_; + size_t count_; }; } // namespace rapidjson diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h index 4128311..31ccfc1 100644 --- a/include/rapidjson/filewritestream.h +++ b/include/rapidjson/filewritestream.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_ @@ -8,68 +28,68 @@ namespace rapidjson { //! Wrapper of C file stream for input using fread(). /*! - \note implements Stream concept + \note implements Stream concept */ class FileWriteStream { public: - typedef char Ch; //!< Character type. Only support char. + typedef char Ch; //!< Character type. Only support char. - FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { - RAPIDJSON_ASSERT(fp_ != 0); - } + FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { + RAPIDJSON_ASSERT(fp_ != 0); + } - void Put(char c) { - if (current_ >= bufferEnd_) - Flush(); + void Put(char c) { + if (current_ >= bufferEnd_) + Flush(); - *current_++ = c; - } + *current_++ = c; + } - void PutN(char c, size_t n) { - size_t avail = static_cast(bufferEnd_ - current_); - while (n > avail) { - memset(current_, c, avail); - current_ += avail; - Flush(); - n -= avail; - avail = static_cast(bufferEnd_ - current_); - } + void PutN(char c, size_t n) { + size_t avail = static_cast(bufferEnd_ - current_); + while (n > avail) { + memset(current_, c, avail); + current_ += avail; + Flush(); + n -= avail; + avail = static_cast(bufferEnd_ - current_); + } - if (n > 0) { - memset(current_, c, n); - current_ += n; - } - } + if (n > 0) { + memset(current_, c, n); + current_ += n; + } + } - void Flush() { - if (current_ != buffer_) { - fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); - current_ = buffer_; - } - } + void Flush() { + if (current_ != buffer_) { + fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + current_ = buffer_; + } + } - // Not implemented - char Peek() const { RAPIDJSON_ASSERT(false); return 0; } - char Take() { RAPIDJSON_ASSERT(false); return 0; } - size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } - char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: - // Prohibit copy constructor & assignment operator. - FileWriteStream(const FileWriteStream&); - FileWriteStream& operator=(const FileWriteStream&); + // Prohibit copy constructor & assignment operator. + FileWriteStream(const FileWriteStream&); + FileWriteStream& operator=(const FileWriteStream&); - FILE* fp_; - char *buffer_; - char *bufferEnd_; - char *current_; + FILE* fp_; + char *buffer_; + char *bufferEnd_; + char *current_; }; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(FileWriteStream& stream, char c, size_t n) { - stream.PutN(c, n); + stream.PutN(c, n); } } // namespace rapidjson diff --git a/include/rapidjson/internal/dtoa.h b/include/rapidjson/internal/dtoa.h index 44f5c11..bef02b0 100644 --- a/include/rapidjson/internal/dtoa.h +++ b/include/rapidjson/internal/dtoa.h @@ -1,5 +1,26 @@ -// Modified from https://github.com/miloyip/dtoa-benchmark/blob/master/src/milo/dtoa_milo.h -// API is changed to return the character passed the end of string, without writing '\0' +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// This is a C++ header-only implementation of Grisu2 algorithm from the publication: +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with +// integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DTOA_ #define RAPIDJSON_DTOA_ @@ -22,385 +43,369 @@ RAPIDJSON_DIAG_OFF(effc++) #endif struct DiyFp { - DiyFp() {} + DiyFp() {} - DiyFp(uint64_t f, int e) : f(f), e(e) {} + DiyFp(uint64_t f, int e) : f(f), e(e) {} - DiyFp(double d) { - union { - double d; - uint64_t u64; - } u = { d }; + DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; - int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize; - uint64_t significand = (u.u64 & kDpSignificandMask); - if (biased_e != 0) { - f = significand + kDpHiddenBit; - e = biased_e - kDpExponentBias; - } - else { - f = significand; - e = kDpMinExponent + 1; - } - } + int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize; + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } - DiyFp operator-(const DiyFp& rhs) const { - return DiyFp(f - rhs.f, e); - } + DiyFp operator-(const DiyFp& rhs) const { + return DiyFp(f - rhs.f, e); + } - DiyFp operator*(const DiyFp& rhs) const { + DiyFp operator*(const DiyFp& rhs) const { #if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t h; - uint64_t l = _umul128(f, rhs.f, &h); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); + uint64_t h; + uint64_t l = _umul128(f, rhs.f, &h); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) - unsigned __int128 p = static_cast(f) * static_cast(rhs.f); - uint64_t h = p >> 64; - uint64_t l = static_cast(p); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); + unsigned __int128 p = static_cast(f) * static_cast(rhs.f); + uint64_t h = p >> 64; + uint64_t l = static_cast(p); + if (l & (uint64_t(1) << 63)) // rounding + h++; + return DiyFp(h, e + rhs.e + 64); #else - const uint64_t M32 = 0xFFFFFFFF; - const uint64_t a = f >> 32; - const uint64_t b = f & M32; - const uint64_t c = rhs.f >> 32; - const uint64_t d = rhs.f & M32; - const uint64_t ac = a * c; - const uint64_t bc = b * c; - const uint64_t ad = a * d; - const uint64_t bd = b * d; - uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); - tmp += 1U << 31; /// mult_round - return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); + tmp += 1U << 31; /// mult_round + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); #endif - } + } - DiyFp Normalize() const { + DiyFp Normalize() const { #if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp(f << (63 - index), e - (63 - index)); #elif defined(__GNUC__) - int s = __builtin_clzll(f) + 1; - return DiyFp(f << s, e - s); + int s = __builtin_clzll(f) + 1; + return DiyFp(f << s, e - s); #else - DiyFp res = *this; - while (!(res.f & kDpHiddenBit)) { - res.f <<= 1; - res.e--; - } - res.f <<= (kDiySignificandSize - kDpSignificandSize - 1); - res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1); - return res; + DiyFp res = *this; + while (!(res.f & kDpHiddenBit)) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 1); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1); + return res; #endif - } + } - DiyFp NormalizeBoundary() const { + DiyFp NormalizeBoundary() const { #if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp (f << (63 - index), e - (63 - index)); + unsigned long index; + _BitScanReverse64(&index, f); + return DiyFp (f << (63 - index), e - (63 - index)); #else - DiyFp res = *this; - while (!(res.f & (kDpHiddenBit << 1))) { - res.f <<= 1; - res.e--; - } - res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); - res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); - return res; + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; #endif - } + } - void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { - DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); - DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); - mi.f <<= mi.e - pl.e; - mi.e = pl.e; - *plus = pl; - *minus = mi; - } + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } - static const int kDiySignificandSize = 64; - static const int kDpSignificandSize = 52; - static const int kDpExponentBias = 0x3FF + kDpSignificandSize; - static const int kDpMinExponent = -kDpExponentBias; - static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMinExponent = -kDpExponentBias; + static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); + static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); + static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); - uint64_t f; - int e; + uint64_t f; + int e; }; inline DiyFp GetCachedPower(int e, int* K) { - // 10^-348, 10^-340, ..., 10^340 - static const uint64_t kCachedPowers_F[] = { - RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), - RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), - RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), - RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), - RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), - RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), - RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), - RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), - RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), - RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), - RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), - RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), - RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), - RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), - RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), - RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), - RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), - RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), - RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), - RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), - RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), - RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), - RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), - RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), - RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), - RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), - RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), - RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), - RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), - RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), - RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), - RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), - RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), - RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), - RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), - RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), - RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), - RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), - RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), - RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), - RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), - RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), - RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), - RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) - }; - static const int16_t kCachedPowers_E[] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, - -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, - -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, - -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, - -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, - 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, - 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, - 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, - 907, 933, 960, 986, 1013, 1039, 1066 - }; + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), + RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), + RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), + RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), + RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), + RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), + RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), + RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), + RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), + RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), + RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), + RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), + RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), + RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), + RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), + RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), + RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), + RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), + RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), + RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), + RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), + RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), + RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), + RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), + RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), + RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), + RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), + RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), + RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), + RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), + RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), + RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), + RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), + RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), + RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), + RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), + RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), + RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), + RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), + RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), + RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), + RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; - //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; - double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive - int k = static_cast(dk); - if (k != dk) - k++; + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (k != dk) + k++; - unsigned index = static_cast((k >> 3) + 1); - *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table - return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { - while (rest < wp_w && delta - rest >= ten_kappa && - (rest + ten_kappa < wp_w || /// closer - wp_w - rest > rest + ten_kappa - wp_w)) { - buffer[len - 1]--; - rest += ten_kappa; - } + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } } inline unsigned CountDecimalDigit32(uint32_t n) { - // Simple pure C++ implementation was faster than __builtin_clz version in this situation. - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1000) return 3; - if (n < 10000) return 4; - if (n < 100000) return 5; - if (n < 1000000) return 6; - if (n < 10000000) return 7; - if (n < 100000000) return 8; - if (n < 1000000000) return 9; - return 10; + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + if (n < 1000000000) return 9; + return 10; } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { - static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; - const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); - const DiyFp wp_w = Mp - W; - uint32_t p1 = static_cast(Mp.f >> -one.e); - uint64_t p2 = Mp.f & (one.f - 1); - int kappa = CountDecimalDigit32(p1); - *len = 0; + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + int kappa = CountDecimalDigit32(p1); + *len = 0; - while (kappa > 0) { - uint32_t d; - switch (kappa) { - case 10: d = p1 / 1000000000; p1 %= 1000000000; break; - case 9: d = p1 / 100000000; p1 %= 100000000; break; - case 8: d = p1 / 10000000; p1 %= 10000000; break; - case 7: d = p1 / 1000000; p1 %= 1000000; break; - case 6: d = p1 / 100000; p1 %= 100000; break; - case 5: d = p1 / 10000; p1 %= 10000; break; - case 4: d = p1 / 1000; p1 %= 1000; break; - case 3: d = p1 / 100; p1 %= 100; break; - case 2: d = p1 / 10; p1 %= 10; break; - case 1: d = p1; p1 = 0; break; - default: + while (kappa > 0) { + uint32_t d; + switch (kappa) { + case 10: d = p1 / 1000000000; p1 %= 1000000000; break; + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default: #if defined(_MSC_VER) - __assume(0); + __assume(0); #elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) - __builtin_unreachable(); + __builtin_unreachable(); #else - d = 0; + d = 0; #endif - } - if (d || *len) - buffer[(*len)++] = '0' + static_cast(d); - kappa--; - uint64_t tmp = (static_cast(p1) << -one.e) + p2; - if (tmp <= delta) { - *K += kappa; - GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); - return; - } - } + } + if (d || *len) + buffer[(*len)++] = '0' + static_cast(d); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } - // kappa = 0 - for (;;) { - p2 *= 10; - delta *= 10; - char d = static_cast(p2 >> -one.e); - if (d || *len) - buffer[(*len)++] = '0' + d; - p2 &= one.f - 1; - kappa--; - if (p2 < delta) { - *K += kappa; - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); - return; - } - } + // kappa = 0 + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = '0' + d; + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); + return; + } + } } inline void Grisu2(double value, char* buffer, int* length, int* K) { - const DiyFp v(value); - DiyFp w_m, w_p; - v.NormalizedBoundaries(&w_m, &w_p); + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); - const DiyFp c_mk = GetCachedPower(w_p.e, K); - const DiyFp W = v.Normalize() * c_mk; - DiyFp Wp = w_p * c_mk; - DiyFp Wm = w_m * c_mk; - Wm.f++; - Wp.f--; - DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); } -//inline const char* GetDigitsLut() { -// static const char cDigitsLut[200] = { -// '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', -// '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', -// '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', -// '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', -// '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', -// '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', -// '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', -// '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', -// '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', -// '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9' -// }; -// return cDigitsLut; -//} - inline char* WriteExponent(int K, char* buffer) { - if (K < 0) { - *buffer++ = '-'; - K = -K; - } + if (K < 0) { + *buffer++ = '-'; + K = -K; + } - if (K >= 100) { - *buffer++ = '0' + static_cast(K / 100); - K %= 100; - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else if (K >= 10) { - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } - else - *buffer++ = '0' + static_cast(K); + if (K >= 100) { + *buffer++ = '0' + static_cast(K / 100); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = '0' + static_cast(K); - return buffer; + return buffer; } inline char* Prettify(char* buffer, int length, int k) { - const int kk = length + k; // 10^(kk-1) <= v < 10^kk + const int kk = length + k; // 10^(kk-1) <= v < 10^kk - if (length <= kk && kk <= 21) { - // 1234e7 -> 12340000000 - for (int i = length; i < kk; i++) - buffer[i] = '0'; - buffer[kk] = '.'; - buffer[kk + 1] = '0'; - return &buffer[kk + 2]; - } - else if (0 < kk && kk <= 21) { - // 1234e-2 -> 12.34 - memmove(&buffer[kk + 1], &buffer[kk], length - kk); - buffer[kk] = '.'; - return &buffer[length + 1]; - } - else if (-6 < kk && kk <= 0) { - // 1234e-6 -> 0.001234 - const int offset = 2 - kk; - memmove(&buffer[offset], &buffer[0], length); - buffer[0] = '0'; - buffer[1] = '.'; - for (int i = 2; i < offset; i++) - buffer[i] = '0'; - return &buffer[length + offset]; - } - else if (length == 1) { - // 1e30 - buffer[1] = 'e'; - return WriteExponent(kk - 1, &buffer[2]); - } - else { - // 1234e30 -> 1.234e33 - memmove(&buffer[2], &buffer[1], length - 1); - buffer[1] = '.'; - buffer[length + 1] = 'e'; - return WriteExponent(kk - 1, &buffer[0 + length + 2]); - } + if (length <= kk && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + memmove(&buffer[kk + 1], &buffer[kk], length - kk); + buffer[kk] = '.'; + return &buffer[length + 1]; + } + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + memmove(&buffer[offset], &buffer[0], length); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + return &buffer[length + offset]; + } + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + else { + // 1234e30 -> 1.234e33 + memmove(&buffer[2], &buffer[1], length - 1); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } } inline char* dtoa(double value, char* buffer) { - if (value == 0) { - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - return &buffer[3]; - } - else { - if (value < 0) { - *buffer++ = '-'; - value = -value; - } - int length, K; - Grisu2(value, buffer, &length, &K); - return Prettify(buffer, length, K); - } + if (value == 0) { + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K); + } } #ifdef __GNUC__ diff --git a/include/rapidjson/internal/itoa.h b/include/rapidjson/internal/itoa.h index 157afb6..2ff199a 100644 --- a/include/rapidjson/internal/itoa.h +++ b/include/rapidjson/internal/itoa.h @@ -1,12 +1,29 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_ namespace rapidjson { namespace internal { -// Modified from https://github.com/miloyip/itoa-benchmark/blob/master/src/branchlut.cpp -// API is changed to return the character passed the end of string, without writing '\0' - inline const char* GetDigitsLut() { static const char cDigitsLut[200] = { '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', @@ -98,12 +115,12 @@ inline char* u32toa(uint32_t value, char* buffer) { } inline char* i32toa(int32_t value, char* buffer) { - if (value < 0) { - *buffer++ = '-'; - value = -value; - } + if (value < 0) { + *buffer++ = '-'; + value = -value; + } - return u32toa(static_cast(value), buffer); + return u32toa(static_cast(value), buffer); } inline char* u64toa(uint64_t value, char* buffer) { @@ -271,16 +288,16 @@ inline char* u64toa(uint64_t value, char* buffer) { *buffer++ = cDigitsLut[d8 + 1]; } - return buffer; + return buffer; } inline char* i64toa(int64_t value, char* buffer) { - if (value < 0) { - *buffer++ = '-'; - value = -value; - } + if (value < 0) { + *buffer++ = '-'; + value = -value; + } - return u64toa(static_cast(value), buffer); + return u64toa(static_cast(value), buffer); } } // namespace internal diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h index b8d3295..62d5224 100644 --- a/include/rapidjson/internal/meta.h +++ b/include/rapidjson/internal/meta.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_ @@ -35,10 +55,10 @@ template struct IsPointer : TrueType {}; template struct IsMoreConst { - enum { Value = - ( IsSame< typename RemoveConst::Type, typename RemoveConst::Type>::Value - && ( IsConst::Value >= IsConst::Value ) ) - }; + enum { Value = + ( IsSame< typename RemoveConst::Type, typename RemoveConst::Type>::Value + && ( IsConst::Value >= IsConst::Value ) ) + }; }; template struct EnableIfCond; @@ -60,15 +80,15 @@ template struct RemoveSfinaeFptr {}; template struct RemoveSfinaeFptr { typedef T Type; }; #define RAPIDJSON_REMOVEFPTR_(type) \ - typename ::rapidjson::internal::RemoveSfinaeFptr \ - < ::rapidjson::internal::SfinaeResultTag&(*) type>::Type + typename ::rapidjson::internal::RemoveSfinaeFptr \ + < ::rapidjson::internal::SfinaeResultTag&(*) type>::Type #define RAPIDJSON_ENABLEIF(cond) \ - typename ::rapidjson::internal::EnableIf \ - ::Type * = NULL + typename ::rapidjson::internal::EnableIf \ + ::Type * = NULL #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ - typename ::rapidjson::internal::DisableIf::Type + typename ::rapidjson::internal::DisableIf::Type } // namespace internal } // namespace rapidjson diff --git a/include/rapidjson/internal/pow10.h b/include/rapidjson/internal/pow10.h index d6b92f0..72e0dac 100644 --- a/include/rapidjson/internal/pow10.h +++ b/include/rapidjson/internal/pow10.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_POW10_ #define RAPIDJSON_POW10_ @@ -6,31 +26,31 @@ namespace internal { //! Computes integer powers of 10 in double (10.0^n). /*! This function uses lookup table for fast and accurate results. - \param n non-negative exponent. Must <= 308. - \return 10.0^n + \param n non-negative exponent. Must <= 308. + \return 10.0^n */ inline double Pow10(int n) { - static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes - 1e+0, - 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, - 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, - 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, - 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, - 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, - 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, - 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, - 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, - 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, - 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, - 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, - 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, - 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, - 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, - 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, - 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 - }; - RAPIDJSON_ASSERT(n >= 0 && n <= 308); - return e[n]; + static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes + 1e+0, + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 + }; + RAPIDJSON_ASSERT(n >= 0 && n <= 308); + return e[n]; } } // namespace internal diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index 8548465..4ab84b1 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ @@ -13,79 +33,79 @@ namespace internal { template class Stack { public: - Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) { - RAPIDJSON_ASSERT(stack_capacity_ > 0); - if (!allocator_) - own_allocator_ = allocator_ = new Allocator(); - stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_); - stack_end_ = stack_ + stack_capacity_; - } + Stack(Allocator* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) { + RAPIDJSON_ASSERT(stack_capacity_ > 0); + if (!allocator_) + own_allocator_ = allocator_ = new Allocator(); + stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_); + stack_end_ = stack_ + stack_capacity_; + } - ~Stack() { - Allocator::Free(stack_); - delete own_allocator_; // Only delete if it is owned by the stack - } + ~Stack() { + Allocator::Free(stack_); + delete own_allocator_; // Only delete if it is owned by the stack + } - void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; } + void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; } - // Optimization note: try to minimize the size of this function for force inline. - // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. - template - RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { - // Expand the stack if needed - if (stack_top_ + sizeof(T) * count >= stack_end_) - Expand(count); + // Optimization note: try to minimize the size of this function for force inline. + // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. + template + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + // Expand the stack if needed + if (stack_top_ + sizeof(T) * count >= stack_end_) + Expand(count); - T* ret = reinterpret_cast(stack_top_); - stack_top_ += sizeof(T) * count; - return ret; - } + T* ret = reinterpret_cast(stack_top_); + stack_top_ += sizeof(T) * count; + return ret; + } - template - T* Pop(size_t count) { - RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); - stack_top_ -= count * sizeof(T); - return reinterpret_cast(stack_top_); - } + template + T* Pop(size_t count) { + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); + stack_top_ -= count * sizeof(T); + return reinterpret_cast(stack_top_); + } - template - T* Top() { - RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); - return reinterpret_cast(stack_top_ - sizeof(T)); - } + template + T* Top() { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stack_top_ - sizeof(T)); + } - template - T* Bottom() { return (T*)stack_; } + template + T* Bottom() { return (T*)stack_; } - Allocator& GetAllocator() { return *allocator_; } - bool Empty() const { return stack_top_ == stack_; } - size_t GetSize() const { return static_cast(stack_top_ - stack_); } - size_t GetCapacity() const { return stack_capacity_; } + Allocator& GetAllocator() { return *allocator_; } + bool Empty() const { return stack_top_ == stack_; } + size_t GetSize() const { return static_cast(stack_top_ - stack_); } + size_t GetCapacity() const { return stack_capacity_; } private: - template - void Expand(size_t count) { - size_t new_capacity = stack_capacity_ * 2; - size_t size = GetSize(); - size_t new_size = GetSize() + sizeof(T) * count; - if (new_capacity < new_size) - new_capacity = new_size; - stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity); - stack_capacity_ = new_capacity; - stack_top_ = stack_ + size; - stack_end_ = stack_ + stack_capacity_; - } + template + void Expand(size_t count) { + size_t new_capacity = stack_capacity_ * 2; + size_t size = GetSize(); + size_t new_size = GetSize() + sizeof(T) * count; + if (new_capacity < new_size) + new_capacity = new_size; + stack_ = (char*)allocator_->Realloc(stack_, stack_capacity_, new_capacity); + stack_capacity_ = new_capacity; + stack_top_ = stack_ + size; + stack_end_ = stack_ + stack_capacity_; + } - // Prohibit copy constructor & assignment operator. - Stack(const Stack&); - Stack& operator=(const Stack&); + // Prohibit copy constructor & assignment operator. + Stack(const Stack&); + Stack& operator=(const Stack&); - Allocator* allocator_; - Allocator* own_allocator_; - char *stack_; - char *stack_top_; - char *stack_end_; - size_t stack_capacity_; + Allocator* allocator_; + Allocator* own_allocator_; + char *stack_; + char *stack_top_; + char *stack_end_; + size_t stack_capacity_; }; } // namespace internal diff --git a/include/rapidjson/internal/strfunc.h b/include/rapidjson/internal/strfunc.h index 0a20c56..80adcb6 100644 --- a/include/rapidjson/internal/strfunc.h +++ b/include/rapidjson/internal/strfunc.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ @@ -5,16 +25,16 @@ namespace rapidjson { namespace internal { //! Custom strlen() which works on different character types. -/*! \tparam Ch Character type (e.g. char, wchar_t, short) - \param s Null-terminated input string. - \return Number of characters in the string. - \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. +/*! \tparam Ch Character type (e.g. char, wchar_t, short) + \param s Null-terminated input string. + \return Number of characters in the string. + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. */ template inline SizeType StrLen(const Ch* s) { - const Ch* p = s; - while (*p) ++p; - return SizeType(p - s); + const Ch* p = s; + while (*p) ++p; + return SizeType(p - s); } } // namespace internal diff --git a/include/rapidjson/memorybuffer.h b/include/rapidjson/memorybuffer.h index 3628ebc..4e82036 100644 --- a/include/rapidjson/memorybuffer.h +++ b/include/rapidjson/memorybuffer.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_ @@ -8,38 +28,38 @@ namespace rapidjson { //! Represents an in-memory output byte stream. /*! - This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. + This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. - It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. + It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. - Differences between MemoryBuffer and StringBuffer: - 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. - 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. + Differences between MemoryBuffer and StringBuffer: + 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. + 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept */ template struct GenericMemoryBuffer { - typedef char Ch; // byte + typedef char Ch; // byte - GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - void Put(Ch c) { *stack_.template Push() = c; } - void Flush() {} + void Put(Ch c) { *stack_.template Push() = c; } + void Flush() {} - void Clear() { stack_.Clear(); } - Ch* Push(size_t count) { return stack_.template Push(count); } - void Pop(size_t count) { stack_.template Pop(count); } + void Clear() { stack_.Clear(); } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } - const Ch* GetBuffer() const { - return stack_.template Bottom(); - } + const Ch* GetBuffer() const { + return stack_.template Bottom(); + } - size_t GetSize() const { return stack_.GetSize(); } + size_t GetSize() const { return stack_.GetSize(); } - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; }; typedef GenericMemoryBuffer<> MemoryBuffer; @@ -47,7 +67,7 @@ typedef GenericMemoryBuffer<> MemoryBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { - memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); + memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); } } // namespace rapidjson diff --git a/include/rapidjson/memorystream.h b/include/rapidjson/memorystream.h index 158fbb5..8701c33 100644 --- a/include/rapidjson/memorystream.h +++ b/include/rapidjson/memorystream.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_ @@ -7,39 +27,39 @@ namespace rapidjson { //! Represents an in-memory input byte stream. /*! - This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. + This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. - It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. + It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. - Differences between MemoryStream and StringStream: - 1. StringStream has encoding but MemoryStream is a byte stream. - 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. - 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). - \note implements Stream concept + Differences between MemoryStream and StringStream: + 1. StringStream has encoding but MemoryStream is a byte stream. + 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. + 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). + \note implements Stream concept */ struct MemoryStream { - typedef char Ch; // byte + typedef char Ch; // byte - MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} + MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} - Ch Peek() const { return *src_; } - Ch Take() { return (src_ == end_) ? '\0' : *src_++; } - size_t Tell() const { return static_cast(src_ - begin_); } + Ch Peek() const { return *src_; } + Ch Take() { return (src_ == end_) ? '\0' : *src_++; } + size_t Tell() const { return static_cast(src_ - begin_); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - // For encoding detection only. - const Ch* Peek4() const { - return Tell() + 4 <= size_ ? src_ : 0; - } + // For encoding detection only. + const Ch* Peek4() const { + return Tell() + 4 <= size_ ? src_ : 0; + } - const Ch* src_; //!< Current read position. - const Ch* begin_; //!< Original head of the string. - const Ch* end_; //!< End of stream. - size_t size_; //!< Size of the stream. + const Ch* src_; //!< Current read position. + const Ch* begin_; //!< Original head of the string. + const Ch* end_; //!< End of stream. + size_t size_; //!< Size of the stream. }; } // namespace rapidjson diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index d351468..b9d7510 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_ @@ -12,166 +32,166 @@ namespace rapidjson { //! Writer with indentation and spacing. /*! - \tparam OutputStream Type of ouptut os. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam Allocator Type of allocator for allocating memory of stack. + \tparam OutputStream Type of ouptut os. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam Allocator Type of allocator for allocating memory of stack. */ template, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> > class PrettyWriter : public Writer { public: - typedef Writer Base; - typedef typename Base::Ch Ch; + typedef Writer Base; + typedef typename Base::Ch Ch; - //! Constructor - /*! \param os Output stream. - \param allocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} - //! Set custom indentation. - /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). - \param indentCharCount Number of indent characters for each indentation level. - \note The default indentation is 4 spaces. - */ - PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { - RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); - indentChar_ = indentChar; - indentCharCount_ = indentCharCount; - return *this; - } + //! Set custom indentation. + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). + \param indentCharCount Number of indent characters for each indentation level. + \note The default indentation is 4 spaces. + */ + PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); + indentChar_ = indentChar; + indentCharCount_ = indentCharCount; + return *this; + } - /*! @name Implementation of Handler - \see Handler - */ - //@{ + /*! @name Implementation of Handler + \see Handler + */ + //@{ - bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } - bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } - bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } - bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } - bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } - bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } - bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } + bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } + bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } + bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } - bool String(const Ch* str, SizeType length, bool copy = false) { - (void)copy; - PrettyPrefix(kStringType); - return Base::WriteString(str, length); - } + bool String(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + PrettyPrefix(kStringType); + return Base::WriteString(str, length); + } - bool StartObject() { - PrettyPrefix(kObjectType); - new (Base::level_stack_.template Push()) typename Base::Level(false); - return Base::WriteStartObject(); - } + bool StartObject() { + PrettyPrefix(kObjectType); + new (Base::level_stack_.template Push()) typename Base::Level(false); + return Base::WriteStartObject(); + } - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - if (!empty) { - Base::os_->Put('\n'); - WriteIndent(); - } - if (!Base::WriteEndObject()) - return false; - if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); - return true; - } + if (!empty) { + Base::os_->Put('\n'); + WriteIndent(); + } + if (!Base::WriteEndObject()) + return false; + if (Base::level_stack_.Empty()) // end of json text + Base::os_->Flush(); + return true; + } - bool StartArray() { - PrettyPrefix(kArrayType); - new (Base::level_stack_.template Push()) typename Base::Level(true); - return Base::WriteStartArray(); - } + bool StartArray() { + PrettyPrefix(kArrayType); + new (Base::level_stack_.template Push()) typename Base::Level(true); + return Base::WriteStartArray(); + } - bool EndArray(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); - bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; + bool EndArray(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); + RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - if (!empty) { - Base::os_->Put('\n'); - WriteIndent(); - } - if (!Base::WriteEndArray()) - return false; - if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); - return true; - } + if (!empty) { + Base::os_->Put('\n'); + WriteIndent(); + } + if (!Base::WriteEndArray()) + return false; + if (Base::level_stack_.Empty()) // end of json text + Base::os_->Flush(); + return true; + } - //@} + //@} - /*! @name Convenience extensions */ - //@{ + /*! @name Convenience extensions */ + //@{ - //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - //@} + //@} protected: - void PrettyPrefix(Type type) { - (void)type; - if (Base::level_stack_.GetSize() != 0) { // this value is not at root - typename Base::Level* level = Base::level_stack_.template Top(); + void PrettyPrefix(Type type) { + (void)type; + if (Base::level_stack_.GetSize() != 0) { // this value is not at root + typename Base::Level* level = Base::level_stack_.template Top(); - if (level->inArray) { - if (level->valueCount > 0) { - Base::os_->Put(','); // add comma if it is not the first element in array - Base::os_->Put('\n'); - } - else - Base::os_->Put('\n'); - WriteIndent(); - } - else { // in object - if (level->valueCount > 0) { - if (level->valueCount % 2 == 0) { - Base::os_->Put(','); - Base::os_->Put('\n'); - } - else { - Base::os_->Put(':'); - Base::os_->Put(' '); - } - } - else - Base::os_->Put('\n'); + if (level->inArray) { + if (level->valueCount > 0) { + Base::os_->Put(','); // add comma if it is not the first element in array + Base::os_->Put('\n'); + } + else + Base::os_->Put('\n'); + WriteIndent(); + } + else { // in object + if (level->valueCount > 0) { + if (level->valueCount % 2 == 0) { + Base::os_->Put(','); + Base::os_->Put('\n'); + } + else { + Base::os_->Put(':'); + Base::os_->Put(' '); + } + } + else + Base::os_->Put('\n'); - if (level->valueCount % 2 == 0) - WriteIndent(); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); - RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. - Base::hasRoot_ = true; - } - } + if (level->valueCount % 2 == 0) + WriteIndent(); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); + RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. + Base::hasRoot_ = true; + } + } - void WriteIndent() { - size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; - PutN(*Base::os_, indentChar_, count); - } + void WriteIndent() { + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; + PutN(*Base::os_, indentChar_, count); + } - Ch indentChar_; - unsigned indentCharCount_; + Ch indentChar_; + unsigned indentCharCount_; private: - // Prohibit copy constructor & assignment operator. - PrettyWriter(const PrettyWriter&); - PrettyWriter& operator=(const PrettyWriter&); + // Prohibit copy constructor & assignment operator. + PrettyWriter(const PrettyWriter&); + PrettyWriter& operator=(const PrettyWriter&); }; } // namespace rapidjson diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index d25f02b..0e81e3b 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_ @@ -5,13 +25,13 @@ // Version 0.1 /*!\file rapidjson.h - \brief common definitions and configuration + \brief common definitions and configuration - \todo Complete Doxygen documentation for configure macros. + \todo Complete Doxygen documentation for configure macros. */ -#include // malloc(), realloc(), free() -#include // memcpy() +#include // malloc(), realloc(), free() +#include // memcpy() /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE @@ -46,17 +66,17 @@ /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ENDIAN -#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine -#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine //! Endianness of the machine. -/*! GCC 4.6 provided macro for detecting endianness of the target machine. But other - compilers may not have this. User can define RAPIDJSON_ENDIAN to either - \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. +/*! GCC 4.6 provided macro for detecting endianness of the target machine. But other + compilers may not have this. User can define RAPIDJSON_ENDIAN to either + \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. - Implemented with reference to - https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html - http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp + Implemented with reference to + https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html + http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp */ #ifndef RAPIDJSON_ENDIAN // Detect with GCC 4.6's macro @@ -67,29 +87,29 @@ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. -# endif // __BYTE_ORDER__ +# endif // __BYTE_ORDER__ // Detect with GLIBC's endian.h # elif defined(__GLIBC__) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif (__BYTE_ORDER == __BIG_ENDIAN) +# elif (__BYTE_ORDER == __BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN -# else +# else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif // __GLIBC__ // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN // Detect with architecture macros # elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) -# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) -# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # else -# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN @@ -98,8 +118,8 @@ //! Data alignment of the machine. /*! - Some machine requires strict data alignment. - Currently the default uses 4 bytes alignment. User can customize this. + Some machine requires strict data alignment. + Currently the default uses 4 bytes alignment. User can customize this. */ #ifndef RAPIDJSON_ALIGN #define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u) @@ -110,9 +130,9 @@ //! Construct a 64-bit literal by a pair of 32-bit integer. /*! - 64-bit literal with or without ULL suffix is prone to compiler warnings. - UINT64_C() is C macro which cause compilation problems. - Use this macro to define 64-bit constants by a pair of 32-bit integer. + 64-bit literal with or without ULL suffix is prone to compiler warnings. + UINT64_C() is C macro which cause compilation problems. + Use this macro to define 64-bit constants by a pair of 32-bit integer. */ #ifndef RAPIDJSON_UINT64_C2 #define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) @@ -148,7 +168,7 @@ typedef unsigned SizeType; //! Assertion. /*! By default, rapidjson uses C assert() for assertion. - User can override it by defining RAPIDJSON_ASSERT(x) macro. + User can override it by defining RAPIDJSON_ASSERT(x) macro. */ #ifndef RAPIDJSON_ASSERT #include @@ -180,13 +200,13 @@ template struct StaticAssertTest {}; //!@endcond /*! \def RAPIDJSON_STATIC_ASSERT - \brief (internal) macro to check for conditions at compile-time - \param x compile-time condition - \hideinitializer + \brief (internal) macro to check for conditions at compile-time + \param x compile-time condition + \hideinitializer */ #define RAPIDJSON_STATIC_ASSERT(x) typedef ::rapidjson::StaticAssertTest<\ - sizeof(::rapidjson::STATIC_ASSERTION_FAILURE)>\ - RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE + sizeof(::rapidjson::STATIC_ASSERTION_FAILURE)>\ + RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif /////////////////////////////////////////////////////////////////////////////// @@ -214,7 +234,7 @@ template struct StaticAssertTest {}; #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) #define RAPIDJSON_DIAG_OFF(x) \ - RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) + RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) // push/pop support in Clang and GCC>=4.6 #if defined(__clang__) || (defined(__GNUC__) && RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) >= RAPIDJSON_VERSION_CODE(4,6,0)) @@ -258,65 +278,65 @@ namespace rapidjson { // Stream /*! \class rapidjson::Stream - \brief Concept for reading and writing characters. + \brief Concept for reading and writing characters. - For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). - For write-only stream, only need to implement Put() and Flush(). + For write-only stream, only need to implement Put() and Flush(). \code concept Stream { - typename Ch; //!< Character type of the stream. + typename Ch; //!< Character type of the stream. - //! Read the current character from stream without moving the read cursor. - Ch Peek() const; + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; - //! Read the current character from stream and moving the read cursor to next character. - Ch Take(); + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); - //! Get the current read cursor. - //! \return Number of characters read from start. - size_t Tell(); + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); - //! Begin writing operation at the current read pointer. - //! \return The begin writer pointer. - Ch* PutBegin(); + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); - //! Write a character. - void Put(Ch c); + //! Write a character. + void Put(Ch c); - //! Flush the buffer. - void Flush(); + //! Flush the buffer. + void Flush(); - //! End the writing operation. - //! \param begin The begin write pointer returned by PutBegin(). - //! \return Number of characters written. - size_t PutEnd(Ch* begin); + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); } \endcode */ //! Provides additional information for stream. /*! - By using traits pattern, this type provides a default configuration for stream. - For custom stream, this type can be specialized for other configuration. - See TEST(Reader, CustomStringStream) in readertest.cpp for example. + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. */ template struct StreamTraits { - //! Whether to make local copy of stream for optimization during parsing. - /*! - By default, for safety, streams do not use local copy optimization. - Stream that can be copied fast should specialize this, like StreamTraits. - */ - enum { copyOptimization = 0 }; + //! Whether to make local copy of stream for optimization during parsing. + /*! + By default, for safety, streams do not use local copy optimization. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + enum { copyOptimization = 0 }; }; //! Put N copies of a character to a stream. template inline void PutN(Stream& stream, Ch c, size_t n) { - for (size_t i = 0; i < n; i++) - stream.Put(c); + for (size_t i = 0; i < n; i++) + stream.Put(c); } /////////////////////////////////////////////////////////////////////////////// @@ -327,26 +347,26 @@ inline void PutN(Stream& stream, Ch c, size_t n) { */ template struct GenericStringStream { - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - GenericStringStream(const Ch *src) : src_(src), head_(src) {} + GenericStringStream(const Ch *src) : src_(src), head_(src) {} - Ch Peek() const { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() const { return static_cast(src_ - head_); } + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. }; template struct StreamTraits > { - enum { copyOptimization = 1 }; + enum { copyOptimization = 1 }; }; //! String stream with UTF8 encoding. @@ -357,37 +377,37 @@ typedef GenericStringStream > StringStream; //! A read-write string stream. /*! This string stream is particularly designed for in-situ parsing. - \note implements Stream concept + \note implements Stream concept */ template struct GenericInsituStringStream { - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} - // Read - Ch Peek() { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() { return static_cast(src_ - head_); } + // Read + Ch Peek() { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() { return static_cast(src_ - head_); } - // Write - void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + // Write + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } - Ch* PutBegin() { return dst_ = src_; } - size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } - void Flush() {} + Ch* PutBegin() { return dst_ = src_; } + size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } + void Flush() {} - Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } - void Pop(size_t count) { dst_ -= count; } + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } + void Pop(size_t count) { dst_ -= count; } - Ch* src_; - Ch* dst_; - Ch* head_; + Ch* src_; + Ch* dst_; + Ch* head_; }; template struct StreamTraits > { - enum { copyOptimization = 1 }; + enum { copyOptimization = 1 }; }; //! Insitu string stream with UTF8 encoding. @@ -398,13 +418,13 @@ typedef GenericInsituStringStream > InsituStringStream; //! Type of JSON value enum Type { - kNullType = 0, //!< null - kFalseType = 1, //!< false - kTrueType = 2, //!< true - kObjectType = 3, //!< object - kArrayType = 4, //!< array - kStringType = 5, //!< string - kNumberType = 6 //!< number + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6 //!< number }; } // namespace rapidjson diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 647ecde..d0f7ea4 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_ @@ -28,27 +48,27 @@ RAPIDJSON_DIAG_OFF(4702) // unreachable code #define RAPIDJSON_NOTHING /* deliberately empty */ #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - if (HasParseError()) { return value; } \ - RAPIDJSON_MULTILINEMACRO_END + RAPIDJSON_MULTILINEMACRO_BEGIN \ + if (HasParseError()) { return value; } \ + RAPIDJSON_MULTILINEMACRO_END #endif #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) #ifndef RAPIDJSON_PARSE_ERROR_NORETURN #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ - parseResult_.Set(parseErrorCode,offset); \ - RAPIDJSON_MULTILINEMACRO_END + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ + parseResult_.Set(parseErrorCode,offset); \ + RAPIDJSON_MULTILINEMACRO_END #endif #ifndef RAPIDJSON_PARSE_ERROR #define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ - RAPIDJSON_MULTILINEMACRO_BEGIN \ - RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ - RAPIDJSON_MULTILINEMACRO_END + RAPIDJSON_MULTILINEMACRO_BEGIN \ + RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ + RAPIDJSON_MULTILINEMACRO_END #endif #include "error/error.h" // ParseErrorCode, ParseResult @@ -62,36 +82,36 @@ namespace rapidjson { /*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream */ enum ParseFlag { - kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer. - kParseInsituFlag = 1, //!< In-situ(destructive) parsing. - kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. - kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. - kParseStopWhenDoneFlag = 8 //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. + kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer. + kParseInsituFlag = 1, //!< In-situ(destructive) parsing. + kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. + kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. + kParseStopWhenDoneFlag = 8 //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. }; /////////////////////////////////////////////////////////////////////////////// // Handler -/*! \class rapidjson::Handler - \brief Concept for receiving events from GenericReader upon parsing. - The functions return true if no error occurs. If they return false, - the event publisher should terminate the process. +/*! \class rapidjson::Handler + \brief Concept for receiving events from GenericReader upon parsing. + The functions return true if no error occurs. If they return false, + the event publisher should terminate the process. \code concept Handler { - typename Ch; + typename Ch; - bool Null(); - bool Bool(bool b); - bool Int(int i); - bool Uint(unsigned i); - bool Int64(int64_t i); - bool Uint64(uint64_t i); - bool Double(double d); - bool String(const Ch* str, SizeType length, bool copy); - bool StartObject(); - bool EndObject(SizeType memberCount); - bool StartArray(); - bool EndArray(SizeType elementCount); + bool Null(); + bool Bool(bool b); + bool Int(int i); + bool Uint(unsigned i); + bool Int64(int64_t i); + bool Uint64(uint64_t i); + bool Double(double d); + bool String(const Ch* str, SizeType length, bool copy); + bool StartObject(); + bool EndObject(SizeType memberCount); + bool StartArray(); + bool EndArray(SizeType elementCount); }; \endcode */ @@ -100,25 +120,25 @@ concept Handler { //! Default implementation of Handler. /*! This can be used as base class of any reader handler. - \note implements Handler concept + \note implements Handler concept */ template > struct BaseReaderHandler { - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - bool Default() { return true; } - bool Null() { return Default(); } - bool Bool(bool) { return Default(); } - bool Int(int) { return Default(); } - bool Uint(unsigned) { return Default(); } - bool Int64(int64_t) { return Default(); } - bool Uint64(uint64_t) { return Default(); } - bool Double(double) { return Default(); } - bool String(const Ch*, SizeType, bool) { return Default(); } - bool StartObject() { return Default(); } - bool EndObject(SizeType) { return Default(); } - bool StartArray() { return Default(); } - bool EndArray(SizeType) { return Default(); } + bool Default() { return true; } + bool Null() { return Default(); } + bool Bool(bool) { return Default(); } + bool Int(int) { return Default(); } + bool Uint(unsigned) { return Default(); } + bool Int64(int64_t) { return Default(); } + bool Uint64(uint64_t) { return Default(); } + bool Double(double) { return Default(); } + bool String(const Ch*, SizeType, bool) { return Default(); } + bool StartObject() { return Default(); } + bool EndObject(SizeType) { return Default(); } + bool StartArray() { return Default(); } + bool EndArray(SizeType) { return Default(); } }; /////////////////////////////////////////////////////////////////////////////// @@ -133,27 +153,27 @@ class StreamLocalCopy; template class StreamLocalCopy { public: - StreamLocalCopy(Stream& original) : s(original), original_(original) {} - ~StreamLocalCopy() { original_ = s; } + StreamLocalCopy(Stream& original) : s(original), original_(original) {} + ~StreamLocalCopy() { original_ = s; } - Stream s; + Stream s; private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; - Stream& original_; + Stream& original_; }; //! Keep reference. template class StreamLocalCopy { public: - StreamLocalCopy(Stream& original) : s(original) {} + StreamLocalCopy(Stream& original) : s(original) {} - Stream& s; + Stream& s; private: - StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; }; } // namespace internal @@ -163,134 +183,134 @@ private: //! Skip the JSON white spaces in a stream. /*! \param is A input stream for skipping white spaces. - \note This function has SSE2/SSE4.2 specialization. + \note This function has SSE2/SSE4.2 specialization. */ template void SkipWhitespace(InputStream& is) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); - while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') - s.Take(); + while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') + s.Take(); } #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { - static const char whitespace[16] = " \n\r\t"; - static const char whitespaces[4][17] = { - " ", - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; + static const char whitespace[16] = " \n\r\t"; + static const char whitespaces[4][17] = { + " ", + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; - // 16-byte align to the lower boundary - const char* ap = reinterpret_cast(reinterpret_cast(p) & ~15); + // 16-byte align to the lower boundary + const char* ap = reinterpret_cast(reinterpret_cast(p) & ~15); - // Test first unaligned characters - // Cannot make use of _mm_cmpistrm() because it stops when encounters '\0' before p - if (ap != p) { - const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); - const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); - const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); - const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); + // Test first unaligned characters + // Cannot make use of _mm_cmpistrm() because it stops when encounters '\0' before p + if (ap != p) { + const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); + const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); + const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); + const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); - unsigned char shift = reinterpret_cast(p) & 15; - const __m128i s = _mm_load_si128(reinterpret_cast(ap)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = (unsigned short)~_mm_movemask_epi8(x); - r = r >> shift << shift; // Clear results before p - if (r != 0) { -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return ap + offset; + unsigned char shift = reinterpret_cast(p) & 15; + const __m128i s = _mm_load_si128(reinterpret_cast(ap)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = (unsigned short)~_mm_movemask_epi8(x); + r = r >> shift << shift; // Clear results before p + if (r != 0) { +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return ap + offset; #else - return ap + __builtin_ffs(r) - 1; + return ap + __builtin_ffs(r) - 1; #endif - } - ap += 16; - } + } + ap += 16; + } - const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); + const __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]); - // The rest of string - for (;; ap += 16) { - const __m128i s = _mm_load_si128((const __m128i *)ap); - const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return ap + offset; + // The rest of string + for (;; ap += 16) { + const __m128i s = _mm_load_si128((const __m128i *)ap); + const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); + if (r != 0) { // some of characters is non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return ap + offset; #else - return ap + __builtin_ffs(r) - 1; + return ap + __builtin_ffs(r) - 1; #endif - } - } + } + } } #elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { - static const char whitespaces[4][17] = { - " ", - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; + static const char whitespaces[4][17] = { + " ", + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; - const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); - const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); - const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); - const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); + const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); + const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); + const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); + const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); - // 16-byte align to the lower boundary - const char* ap = reinterpret_cast(reinterpret_cast(p) & ~15); + // 16-byte align to the lower boundary + const char* ap = reinterpret_cast(reinterpret_cast(p) & ~15); - // Test first unaligned characters - if (ap != p) { - unsigned char shift = reinterpret_cast(p) & 15; - const __m128i s = _mm_load_si128(reinterpret_cast(ap)); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = (unsigned short)~_mm_movemask_epi8(x); - r = r >> shift << shift; // Clear results before p - if (r != 0) { -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return ap + offset; + // Test first unaligned characters + if (ap != p) { + unsigned char shift = reinterpret_cast(p) & 15; + const __m128i s = _mm_load_si128(reinterpret_cast(ap)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = (unsigned short)~_mm_movemask_epi8(x); + r = r >> shift << shift; // Clear results before p + if (r != 0) { +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return ap + offset; #else - return ap + __builtin_ffs(r) - 1; + return ap + __builtin_ffs(r) - 1; #endif - } - ap += 16; - } + } + ap += 16; + } - // The rest of string - for (;; ap += 16) { - const __m128i s = _mm_load_si128((const __m128i *)ap); - __m128i x = _mm_cmpeq_epi8(s, w0); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); - x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = (unsigned short)~_mm_movemask_epi8(x); - if (r != 0) { // some of characters may be non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return ap + offset; + // The rest of string + for (;; ap += 16) { + const __m128i s = _mm_load_si128((const __m128i *)ap); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = (unsigned short)~_mm_movemask_epi8(x); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return ap + offset; #else - return ap + __builtin_ffs(r) - 1; + return ap + __builtin_ffs(r) - 1; #endif - } - } + } + } } #endif // RAPIDJSON_SSE2 @@ -298,12 +318,12 @@ inline const char *SkipWhitespace_SIMD(const char* p) { #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream template<> inline void SkipWhitespace(InsituStringStream& is) { - is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); + is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); } //! Template function specialization for StringStream template<> inline void SkipWhitespace(StringStream& is) { - is.src_ = SkipWhitespace_SIMD(is.src_); + is.src_ = SkipWhitespace_SIMD(is.src_); } #endif // RAPIDJSON_SIMD @@ -323,966 +343,966 @@ template<> inline void SkipWhitespace(StringStream& is) { A GenericReader object can be reused for parsing multiple JSON text. \tparam SourceEncoding Encoding of the input stream. - \tparam TargetEncoding Encoding of the parse output. + \tparam TargetEncoding Encoding of the parse output. \tparam Allocator Allocator type for stack. */ template > class GenericReader { public: - typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type + typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type - //! Constructor. - /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) - \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) - */ - GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {} + //! Constructor. + /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) + */ + GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseResult_() {} - //! Parse JSON text. - /*! \tparam parseFlags Combination of \ref ParseFlag. - \tparam InputStream Type of input stream, implementing Stream concept. - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - if (parseFlags & kParseIterativeFlag) - return IterativeParse(is, handler); + //! Parse JSON text. + /*! \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + if (parseFlags & kParseIterativeFlag) + return IterativeParse(is, handler); - parseResult_.Clear(); + parseResult_.Clear(); - ClearStackOnExit scope(*this); + ClearStackOnExit scope(*this); - SkipWhitespace(is); + SkipWhitespace(is); - if (is.Peek() == '\0') { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - else { - switch (is.Peek()) { - case '{': ParseObject(is, handler); break; - case '[': ParseArray(is, handler); break; - default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell()); - } - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + if (is.Peek() == '\0') { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + else { + switch (is.Peek()) { + case '{': ParseObject(is, handler); break; + case '[': ParseArray(is, handler); break; + default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell()); + } + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - if (!(parseFlags & kParseStopWhenDoneFlag)) { - SkipWhitespace(is); + if (!(parseFlags & kParseStopWhenDoneFlag)) { + SkipWhitespace(is); - if (is.Peek() != '\0') { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - } - } - } + if (is.Peek() != '\0') { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); + } + } + } - return parseResult_; - } + return parseResult_; + } - //! Parse JSON text (with \ref kParseDefaultFlags) - /*! \tparam InputStream Type of input stream, implementing Stream concept - \tparam Handler Type of handler, implementing Handler concept. - \param is Input stream to be parsed. - \param handler The handler to receive events. - \return Whether the parsing is successful. - */ - template - ParseResult Parse(InputStream& is, Handler& handler) { - return Parse(is, handler); - } + //! Parse JSON text (with \ref kParseDefaultFlags) + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + ParseResult Parse(InputStream& is, Handler& handler) { + return Parse(is, handler); + } - //! Whether a parse error has occured in the last parsing. - bool HasParseError() const { return parseResult_.IsError(); } - - //! Get the \ref ParseErrorCode of last parsing. - ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } + //! Whether a parse error has occured in the last parsing. + bool HasParseError() const { return parseResult_.IsError(); } + + //! Get the \ref ParseErrorCode of last parsing. + ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } - //! Get the position of last parsing error in input, 0 otherwise. - size_t GetErrorOffset() const { return parseResult_.Offset(); } + //! Get the position of last parsing error in input, 0 otherwise. + size_t GetErrorOffset() const { return parseResult_.Offset(); } private: - // Prohibit copy constructor & assignment operator. - GenericReader(const GenericReader&); - GenericReader& operator=(const GenericReader&); + // Prohibit copy constructor & assignment operator. + GenericReader(const GenericReader&); + GenericReader& operator=(const GenericReader&); - void ClearStack() { stack_.Clear(); } + void ClearStack() { stack_.Clear(); } - // clear stack on any exit from ParseStream, e.g. due to exception - struct ClearStackOnExit { - explicit ClearStackOnExit(GenericReader& r) : r_(r) {} - ~ClearStackOnExit() { r_.ClearStack(); } - private: - GenericReader& r_; - ClearStackOnExit(const ClearStackOnExit&); - ClearStackOnExit& operator=(const ClearStackOnExit&); - }; + // clear stack on any exit from ParseStream, e.g. due to exception + struct ClearStackOnExit { + explicit ClearStackOnExit(GenericReader& r) : r_(r) {} + ~ClearStackOnExit() { r_.ClearStack(); } + private: + GenericReader& r_; + ClearStackOnExit(const ClearStackOnExit&); + ClearStackOnExit& operator=(const ClearStackOnExit&); + }; - // Parse object: { string : value, ... } - template - void ParseObject(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '{'); - is.Take(); // Skip '{' - - if (!handler.StartObject()) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + // Parse object: { string : value, ... } + template + void ParseObject(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '{'); + is.Take(); // Skip '{' + + if (!handler.StartObject()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - SkipWhitespace(is); + SkipWhitespace(is); - if (is.Peek() == '}') { - is.Take(); - if (!handler.EndObject(0)) // empty object - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } + if (is.Peek() == '}') { + is.Take(); + if (!handler.EndObject(0)) // empty object + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } - for (SizeType memberCount = 0;;) { - if (is.Peek() != '"') - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + for (SizeType memberCount = 0;;) { + if (is.Peek() != '"') + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); - ParseString(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + ParseString(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SkipWhitespace(is); + SkipWhitespace(is); - if (is.Take() != ':') - RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + if (is.Take() != ':') + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - SkipWhitespace(is); + SkipWhitespace(is); - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SkipWhitespace(is); + SkipWhitespace(is); - ++memberCount; + ++memberCount; - switch (is.Take()) { - case ',': SkipWhitespace(is); break; - case '}': - if (!handler.EndObject(memberCount)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - else - return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); - } - } - } + switch (is.Take()) { + case ',': SkipWhitespace(is); break; + case '}': + if (!handler.EndObject(memberCount)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + else + return; + default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + } + } + } - // Parse array: [ value, ... ] - template - void ParseArray(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == '['); - is.Take(); // Skip '[' - - if (!handler.StartArray()) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespace(is); + // Parse array: [ value, ... ] + template + void ParseArray(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == '['); + is.Take(); // Skip '[' + + if (!handler.StartArray()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespace(is); - if (is.Peek() == ']') { - is.Take(); - if (!handler.EndArray(0)) // empty array - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - return; - } + if (is.Peek() == ']') { + is.Take(); + if (!handler.EndArray(0)) // empty array + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } - for (SizeType elementCount = 0;;) { - ParseValue(is, handler); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + for (SizeType elementCount = 0;;) { + ParseValue(is, handler); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - ++elementCount; - SkipWhitespace(is); + ++elementCount; + SkipWhitespace(is); - switch (is.Take()) { - case ',': SkipWhitespace(is); break; - case ']': - if (!handler.EndArray(elementCount)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - else - return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); - } - } - } + switch (is.Take()) { + case ',': SkipWhitespace(is); break; + case ']': + if (!handler.EndArray(elementCount)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + else + return; + default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + } + } + } - template - void ParseNull(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'n'); - is.Take(); + template + void ParseNull(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'n'); + is.Take(); - if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { - if (!handler.Null()) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); - } + if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { + if (!handler.Null()) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + } - template - void ParseTrue(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 't'); - is.Take(); + template + void ParseTrue(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 't'); + is.Take(); - if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { - if (!handler.Bool(true)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); - } + if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { + if (!handler.Bool(true)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + } - template - void ParseFalse(InputStream& is, Handler& handler) { - RAPIDJSON_ASSERT(is.Peek() == 'f'); - is.Take(); + template + void ParseFalse(InputStream& is, Handler& handler) { + RAPIDJSON_ASSERT(is.Peek() == 'f'); + is.Take(); - if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { - if (!handler.Bool(false)) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); - } + if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { + if (!handler.Bool(false)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + } - // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). - template - unsigned ParseHex4(InputStream& is) { - unsigned codepoint = 0; - for (int i = 0; i < 4; i++) { - Ch c = is.Take(); - codepoint <<= 4; - codepoint += static_cast(c); - if (c >= '0' && c <= '9') - codepoint -= '0'; - else if (c >= 'A' && c <= 'F') - codepoint -= 'A' - 10; - else if (c >= 'a' && c <= 'f') - codepoint -= 'a' - 10; - else { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); - RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); - } - } - return codepoint; - } + // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). + template + unsigned ParseHex4(InputStream& is) { + unsigned codepoint = 0; + for (int i = 0; i < 4; i++) { + Ch c = is.Take(); + codepoint <<= 4; + codepoint += static_cast(c); + if (c >= '0' && c <= '9') + codepoint -= '0'; + else if (c >= 'A' && c <= 'F') + codepoint -= 'A' - 10; + else if (c >= 'a' && c <= 'f') + codepoint -= 'a' - 10; + else { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); + } + } + return codepoint; + } - class StackStream { - public: - typedef typename TargetEncoding::Ch Ch; + class StackStream { + public: + typedef typename TargetEncoding::Ch Ch; - StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} - RAPIDJSON_FORCEINLINE void Put(Ch c) { - *stack_.template Push() = c; - ++length_; - } - internal::Stack& stack_; - SizeType length_; + StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} + RAPIDJSON_FORCEINLINE void Put(Ch c) { + *stack_.template Push() = c; + ++length_; + } + internal::Stack& stack_; + SizeType length_; - private: - StackStream(const StackStream&); - StackStream& operator=(const StackStream&); - }; + private: + StackStream(const StackStream&); + StackStream& operator=(const StackStream&); + }; - // Parse string and generate String event. Different code paths for kParseInsituFlag. - template - void ParseString(InputStream& is, Handler& handler) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); + // Parse string and generate String event. Different code paths for kParseInsituFlag. + template + void ParseString(InputStream& is, Handler& handler) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); - if (parseFlags & kParseInsituFlag) { - typename InputStream::Ch *head = s.PutBegin(); - ParseStringToStream(s, s); - 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()); - } - 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 (parseFlags & kParseInsituFlag) { + typename InputStream::Ch *head = s.PutBegin(); + ParseStringToStream(s, s); + 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()); + } + 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()); + } + } - // Parse string to an output is - // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. - template - RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { + // Parse string to an output is + // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. + template + RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { #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,'/', - Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, - 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, - 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 - }; + static const char escape[256] = { + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 + }; #undef Z16 - RAPIDJSON_ASSERT(is.Peek() == '\"'); - is.Take(); // Skip '\"' + RAPIDJSON_ASSERT(is.Peek() == '\"'); + is.Take(); // Skip '\"' - for (;;) { - Ch c = is.Peek(); - if (c == '\\') { // Escape - is.Take(); - Ch e = is.Take(); - if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { - os.Put(escape[(unsigned char)e]); - } - else if (e == 'u') { // Unicode - unsigned codepoint = ParseHex4(is); - if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { - // Handle UTF-16 surrogate pair - if (is.Take() != '\\' || is.Take() != 'u') - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); - unsigned codepoint2 = ParseHex4(is); - if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); - codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; - } - TEncoding::Encode(os, codepoint); - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); - } - else if (c == '"') { // Closing double quote - is.Take(); - os.Put('\0'); // null-terminate the string - return; - } - else if (c == '\0') - RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); - else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); - else { - if (parseFlags & kParseValidateEncodingFlag ? - !Transcoder::Validate(is, os) : - !Transcoder::Transcode(is, os)) - RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); - } - } - } + for (;;) { + Ch c = is.Peek(); + if (c == '\\') { // Escape + is.Take(); + Ch e = is.Take(); + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { + os.Put(escape[(unsigned char)e]); + } + else if (e == 'u') { // Unicode + unsigned codepoint = ParseHex4(is); + if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { + // Handle UTF-16 surrogate pair + if (is.Take() != '\\' || is.Take() != 'u') + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); + unsigned codepoint2 = ParseHex4(is); + if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; + } + TEncoding::Encode(os, codepoint); + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); + } + else if (c == '"') { // Closing double quote + is.Take(); + os.Put('\0'); // null-terminate the string + return; + } + else if (c == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); + else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); + else { + if (parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : + !Transcoder::Transcode(is, os)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); + } + } + } - inline double StrtodFastPath(double significand, int exp) { - // Fast path only works on limited range of values. - // But for simplicity and performance, currently only implement this. - // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ - if (exp < -308) - return 0.0; - else if (exp >= 0) - return significand * internal::Pow10(exp); - else - return significand / internal::Pow10(-exp); - } + inline double StrtodFastPath(double significand, int exp) { + // Fast path only works on limited range of values. + // But for simplicity and performance, currently only implement this. + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ + if (exp < -308) + return 0.0; + else if (exp >= 0) + return significand * internal::Pow10(exp); + else + return significand / internal::Pow10(-exp); + } - template - void ParseNumber(InputStream& is, Handler& handler) { - internal::StreamLocalCopy copy(is); - InputStream& s(copy.s); + template + void ParseNumber(InputStream& is, Handler& handler) { + internal::StreamLocalCopy copy(is); + InputStream& s(copy.s); - // Parse minus - bool minus = false; - if (s.Peek() == '-') { - minus = true; - s.Take(); - } + // Parse minus + bool minus = false; + if (s.Peek() == '-') { + minus = true; + s.Take(); + } - // Parse int: zero / ( digit1-9 *DIGIT ) - unsigned i = 0; - bool try64bit = false; - if (s.Peek() == '0') { - i = 0; - s.Take(); - } - else if (s.Peek() >= '1' && s.Peek() <= '9') { - i = static_cast(s.Take() - '0'); + // Parse int: zero / ( digit1-9 *DIGIT ) + unsigned i = 0; + bool try64bit = false; + if (s.Peek() == '0') { + i = 0; + s.Take(); + } + else if (s.Peek() >= '1' && s.Peek() <= '9') { + i = static_cast(s.Take() - '0'); - if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i >= 214748364) { // 2^31 = 2147483648 - if (i != 214748364 || s.Peek() > '8') { - try64bit = true; - break; - } - } - i = i * 10 + static_cast(s.Take() - '0'); - } - else - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i >= 429496729) { // 2^32 - 1 = 4294967295 - if (i != 429496729 || s.Peek() > '5') { - try64bit = true; - break; - } - } - i = i * 10 + static_cast(s.Take() - '0'); - } - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + if (minus) + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i >= 214748364) { // 2^31 = 2147483648 + if (i != 214748364 || s.Peek() > '8') { + try64bit = true; + break; + } + } + i = i * 10 + static_cast(s.Take() - '0'); + } + else + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i >= 429496729) { // 2^32 - 1 = 4294967295 + if (i != 429496729 || s.Peek() > '5') { + try64bit = true; + break; + } + } + i = i * 10 + static_cast(s.Take() - '0'); + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); - // Parse 64bit int - uint64_t i64 = 0; - bool useDouble = false; - if (try64bit) { - i64 = i; - if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 - if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.Take() - '0'); - } - else - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 - if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { - useDouble = true; - break; - } - i64 = i64 * 10 + static_cast(s.Take() - '0'); - } - } + // Parse 64bit int + uint64_t i64 = 0; + bool useDouble = false; + if (try64bit) { + i64 = i; + if (minus) + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 + if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.Take() - '0'); + } + else + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 + if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { + useDouble = true; + break; + } + i64 = i64 * 10 + static_cast(s.Take() - '0'); + } + } - // Force double for big integer - double d = 0.0; - if (useDouble) { - d = (double)i64; - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (d >= 1E307) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); - d = d * 10 + (s.Take() - '0'); - } - } + // Force double for big integer + double d = 0.0; + if (useDouble) { + d = (double)i64; + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (d >= 1E307) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + d = d * 10 + (s.Take() - '0'); + } + } - // Parse frac = decimal-point 1*DIGIT - int expFrac = 0; - if (s.Peek() == '.') { - if (!useDouble) { - d = try64bit ? (double)i64 : (double)i; - useDouble = true; - } - s.Take(); + // Parse frac = decimal-point 1*DIGIT + int expFrac = 0; + if (s.Peek() == '.') { + if (!useDouble) { + d = try64bit ? (double)i64 : (double)i; + useDouble = true; + } + s.Take(); - if (s.Peek() >= '0' && s.Peek() <= '9') { - d = d * 10 + (s.Take() - '0'); - --expFrac; - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); + if (s.Peek() >= '0' && s.Peek() <= '9') { + d = d * 10 + (s.Take() - '0'); + --expFrac; + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (expFrac > -16) { - d = d * 10 + (s.Peek() - '0'); - --expFrac; - } - s.Take(); - } - } + while (s.Peek() >= '0' && s.Peek() <= '9') { + if (expFrac > -16) { + d = d * 10 + (s.Peek() - '0'); + --expFrac; + } + s.Take(); + } + } - // Parse exp = e [ minus / plus ] 1*DIGIT - int exp = 0; - if (s.Peek() == 'e' || s.Peek() == 'E') { - if (!useDouble) { - d = try64bit ? (double)i64 : (double)i; - useDouble = true; - } - s.Take(); + // Parse exp = e [ minus / plus ] 1*DIGIT + int exp = 0; + if (s.Peek() == 'e' || s.Peek() == 'E') { + if (!useDouble) { + d = try64bit ? (double)i64 : (double)i; + useDouble = true; + } + s.Take(); - bool expMinus = false; - if (s.Peek() == '+') - s.Take(); - else if (s.Peek() == '-') { - s.Take(); - expMinus = true; - } + bool expMinus = false; + if (s.Peek() == '+') + s.Take(); + else if (s.Peek() == '-') { + s.Take(); + expMinus = true; + } - if (s.Peek() >= '0' && s.Peek() <= '9') { - exp = s.Take() - '0'; - while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); - if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); - } - } - else - RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); + if (s.Peek() >= '0' && s.Peek() <= '9') { + exp = s.Take() - '0'; + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + } + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); - if (expMinus) - exp = -exp; - } + if (expMinus) + exp = -exp; + } - // Finish parsing, call event according to the type of number. - bool cont = true; - if (useDouble) { - int expSum = exp + expFrac; - if (expSum < -308) { - // Prevent expSum < -308, making Pow10(expSum) = 0 - d = StrtodFastPath(d, exp); - d = StrtodFastPath(d, expFrac); - } - else - d = StrtodFastPath(d, expSum); + // Finish parsing, call event according to the type of number. + bool cont = true; + if (useDouble) { + int expSum = exp + expFrac; + if (expSum < -308) { + // Prevent expSum < -308, making Pow10(expSum) = 0 + d = StrtodFastPath(d, exp); + d = StrtodFastPath(d, expFrac); + } + else + d = StrtodFastPath(d, expSum); - cont = handler.Double(minus ? -d : d); - } - else { - if (try64bit) { - if (minus) - cont = handler.Int64(-(int64_t)i64); - else - cont = handler.Uint64(i64); - } - else { - if (minus) - cont = handler.Int(-(int)i); - else - cont = handler.Uint(i); - } - } - if (!cont) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); - } + cont = handler.Double(minus ? -d : d); + } + else { + if (try64bit) { + if (minus) + cont = handler.Int64(-(int64_t)i64); + else + cont = handler.Uint64(i64); + } + else { + if (minus) + cont = handler.Int(-(int)i); + else + cont = handler.Uint(i); + } + } + if (!cont) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + } - // Parse any JSON value - template - void ParseValue(InputStream& is, Handler& handler) { - switch (is.Peek()) { - case 'n': ParseNull (is, handler); break; - case 't': ParseTrue (is, handler); break; - case 'f': ParseFalse (is, handler); break; - case '"': ParseString(is, handler); break; - case '{': ParseObject(is, handler); break; - case '[': ParseArray (is, handler); break; - default : ParseNumber(is, handler); - } - } + // Parse any JSON value + template + void ParseValue(InputStream& is, Handler& handler) { + switch (is.Peek()) { + case 'n': ParseNull (is, handler); break; + case 't': ParseTrue (is, handler); break; + case 'f': ParseFalse (is, handler); break; + case '"': ParseString(is, handler); break; + case '{': ParseObject(is, handler); break; + case '[': ParseArray (is, handler); break; + default : ParseNumber(is, handler); + } + } - // Iterative Parsing + // Iterative Parsing - // States - enum IterativeParsingState { - IterativeParsingStartState = 0, - IterativeParsingFinishState, - IterativeParsingErrorState, + // States + enum IterativeParsingState { + IterativeParsingStartState = 0, + IterativeParsingFinishState, + IterativeParsingErrorState, - // Object states - IterativeParsingObjectInitialState, - IterativeParsingMemberKeyState, - IterativeParsingKeyValueDelimiterState, - IterativeParsingMemberValueState, - IterativeParsingMemberDelimiterState, - IterativeParsingObjectFinishState, + // Object states + IterativeParsingObjectInitialState, + IterativeParsingMemberKeyState, + IterativeParsingKeyValueDelimiterState, + IterativeParsingMemberValueState, + IterativeParsingMemberDelimiterState, + IterativeParsingObjectFinishState, - // Array states - IterativeParsingArrayInitialState, - IterativeParsingElementState, - IterativeParsingElementDelimiterState, - IterativeParsingArrayFinishState, + // Array states + IterativeParsingArrayInitialState, + IterativeParsingElementState, + IterativeParsingElementDelimiterState, + IterativeParsingArrayFinishState, - cIterativeParsingStateCount - }; + cIterativeParsingStateCount + }; - // Tokens - enum Token { - LeftBracketToken = 0, - RightBracketToken, + // Tokens + enum Token { + LeftBracketToken = 0, + RightBracketToken, - LeftCurlyBracketToken, - RightCurlyBracketToken, + LeftCurlyBracketToken, + RightCurlyBracketToken, - CommaToken, - ColonToken, + CommaToken, + ColonToken, - StringToken, - FalseToken, - TrueToken, - NullToken, - NumberToken, + StringToken, + FalseToken, + TrueToken, + NullToken, + NumberToken, - kTokenCount - }; + kTokenCount + }; - RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { #define N NumberToken #define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N - // Maps from ASCII to Token - static const unsigned char tokenMap[256] = { - N16, // 00~0F - N16, // 10~1F - N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F - N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F - N16, // 40~4F - N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F - N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F - N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F - N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF - }; + // Maps from ASCII to Token + static const unsigned char tokenMap[256] = { + N16, // 00~0F + N16, // 10~1F + N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F + N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F + N16, // 40~4F + N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F + N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F + N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F + N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF + }; #undef N #undef N16 - - if (sizeof(Ch) == 1 || unsigned(c) < 256) - return (Token)tokenMap[(unsigned char)c]; - else - return NumberToken; - } + + if (sizeof(Ch) == 1 || unsigned(c) < 256) + return (Token)tokenMap[(unsigned char)c]; + else + return NumberToken; + } - RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { - // current state x one lookahead token -> new state - static const char G[cIterativeParsingStateCount][kTokenCount] = { - // Start - { - IterativeParsingArrayInitialState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ObjectInitial - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberKey - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingKeyValueDelimiterState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, - // MemberValue - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingMemberDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ObjectFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // ArrayInitial - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // Element - { - IterativeParsingErrorState, // Left bracket - IterativeParsingArrayFinishState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingElementDelimiterState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingErrorState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, - // ElementDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, - // ArrayFinish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - } - }; // End of G + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { + // current state x one lookahead token -> new state + static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Start + { + IterativeParsingArrayInitialState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ObjectInitial + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberKey + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingKeyValueDelimiterState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // KeyValueDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, + // MemberValue + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingMemberDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // MemberDelimiter + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ObjectFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // ArrayInitial + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // Element + { + IterativeParsingErrorState, // Left bracket + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingErrorState, // Right curly bracket + IterativeParsingElementDelimiterState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingErrorState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // ElementDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + } + }; // End of G - return (IterativeParsingState)G[state][token]; - } + return (IterativeParsingState)G[state][token]; + } - // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). - // May return a new state on state pop. - template - RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { - switch (dst) { - case IterativeParsingStartState: - RAPIDJSON_ASSERT(false); - return IterativeParsingErrorState; + // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). + // May return a new state on state pop. + template + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { + switch (dst) { + case IterativeParsingStartState: + RAPIDJSON_ASSERT(false); + return IterativeParsingErrorState; - case IterativeParsingFinishState: - return dst; + case IterativeParsingFinishState: + return dst; - case IterativeParsingErrorState: - return dst; + case IterativeParsingErrorState: + return dst; - case IterativeParsingObjectInitialState: - case IterativeParsingArrayInitialState: - { - // Push the state(Element or MemeberValue) if we are nested in another array or value of member. - // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. - IterativeParsingState n = src; - if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) - n = IterativeParsingElementState; - else if (src == IterativeParsingKeyValueDelimiterState) - n = IterativeParsingMemberValueState; - // Push current state. - *stack_.template Push(1) = n; - // Initialize and push the member/element count. - *stack_.template Push(1) = 0; - // Call handler - bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return dst; - } - } + case IterativeParsingObjectInitialState: + case IterativeParsingArrayInitialState: + { + // Push the state(Element or MemeberValue) if we are nested in another array or value of member. + // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. + IterativeParsingState n = src; + if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) + n = IterativeParsingElementState; + else if (src == IterativeParsingKeyValueDelimiterState) + n = IterativeParsingMemberValueState; + // Push current state. + *stack_.template Push(1) = n; + // Initialize and push the member/element count. + *stack_.template Push(1) = 0; + // Call handler + bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return dst; + } + } - case IterativeParsingMemberKeyState: - ParseString(is, handler); - if (HasParseError()) - return IterativeParsingErrorState; - else - return dst; + case IterativeParsingMemberKeyState: + ParseString(is, handler); + if (HasParseError()) + return IterativeParsingErrorState; + else + return dst; - case IterativeParsingKeyValueDelimiterState: - if (token == ColonToken) { - is.Take(); - return dst; - } - else - return IterativeParsingErrorState; + case IterativeParsingKeyValueDelimiterState: + if (token == ColonToken) { + is.Take(); + return dst; + } + else + return IterativeParsingErrorState; - case IterativeParsingMemberValueState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; + case IterativeParsingMemberValueState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; - case IterativeParsingElementState: - // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. - ParseValue(is, handler); - if (HasParseError()) { - return IterativeParsingErrorState; - } - return dst; + case IterativeParsingElementState: + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. + ParseValue(is, handler); + if (HasParseError()) { + return IterativeParsingErrorState; + } + return dst; - case IterativeParsingMemberDelimiterState: - case IterativeParsingElementDelimiterState: - is.Take(); - // Update member/element count. - *stack_.template Top() = *stack_.template Top() + 1; - return dst; + case IterativeParsingMemberDelimiterState: + case IterativeParsingElementDelimiterState: + is.Take(); + // Update member/element count. + *stack_.template Top() = *stack_.template Top() + 1; + return dst; - case IterativeParsingObjectFinishState: - { - // Get member count. - SizeType c = *stack_.template Pop(1); - // If the object is not empty, count the last member. - if (src == IterativeParsingMemberValueState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndObject(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } + case IterativeParsingObjectFinishState: + { + // Get member count. + SizeType c = *stack_.template Pop(1); + // If the object is not empty, count the last member. + if (src == IterativeParsingMemberValueState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndObject(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } - case IterativeParsingArrayFinishState: - { - // Get element count. - SizeType c = *stack_.template Pop(1); - // If the array is not empty, count the last element. - if (src == IterativeParsingElementState) - ++c; - // Restore the state. - IterativeParsingState n = static_cast(*stack_.template Pop(1)); - // Transit to Finish state if this is the topmost scope. - if (n == IterativeParsingStartState) - n = IterativeParsingFinishState; - // Call handler - bool hr = handler.EndArray(c); - // On handler short circuits the parsing. - if (!hr) { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); - return IterativeParsingErrorState; - } - else { - is.Take(); - return n; - } - } + case IterativeParsingArrayFinishState: + { + // Get element count. + SizeType c = *stack_.template Pop(1); + // If the array is not empty, count the last element. + if (src == IterativeParsingElementState) + ++c; + // Restore the state. + IterativeParsingState n = static_cast(*stack_.template Pop(1)); + // Transit to Finish state if this is the topmost scope. + if (n == IterativeParsingStartState) + n = IterativeParsingFinishState; + // Call handler + bool hr = handler.EndArray(c); + // On handler short circuits the parsing. + if (!hr) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); + return IterativeParsingErrorState; + } + else { + is.Take(); + return n; + } + } - default: - RAPIDJSON_ASSERT(false); - return IterativeParsingErrorState; - } - } + default: + RAPIDJSON_ASSERT(false); + return IterativeParsingErrorState; + } + } - template - void HandleError(IterativeParsingState src, InputStream& is) { - if (HasParseError()) { - // Error flag has been set. - return; - } - - switch (src) { - case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(is.Peek() == '\0' ? kParseErrorDocumentEmpty : kParseErrorDocumentRootNotObjectOrArray, is.Tell()); - case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); - case IterativeParsingObjectInitialState: - case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); - case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); - case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); - default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - } - } + template + void HandleError(IterativeParsingState src, InputStream& is) { + if (HasParseError()) { + // Error flag has been set. + return; + } + + switch (src) { + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(is.Peek() == '\0' ? kParseErrorDocumentEmpty : kParseErrorDocumentRootNotObjectOrArray, is.Tell()); + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); + case IterativeParsingObjectInitialState: + case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); + case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); + case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + } + } - template - ParseResult IterativeParse(InputStream& is, Handler& handler) { - parseResult_.Clear(); - ClearStackOnExit scope(*this); - IterativeParsingState state = IterativeParsingStartState; + template + ParseResult IterativeParse(InputStream& is, Handler& handler) { + parseResult_.Clear(); + ClearStackOnExit scope(*this); + IterativeParsingState state = IterativeParsingStartState; - SkipWhitespace(is); - while (is.Peek() != '\0') { - Token t = Tokenize(is.Peek()); - IterativeParsingState n = Predict(state, t); - IterativeParsingState d = Transit(state, t, n, is, handler); + SkipWhitespace(is); + while (is.Peek() != '\0') { + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state, t); + IterativeParsingState d = Transit(state, t, n, is, handler); - if (d == IterativeParsingErrorState) { - HandleError(state, is); - break; - } + if (d == IterativeParsingErrorState) { + HandleError(state, is); + break; + } - state = d; + state = d; - // Do not further consume streams if a root JSON has been parsed. - if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) - break; + // Do not further consume streams if a root JSON has been parsed. + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) + break; - SkipWhitespace(is); - } + SkipWhitespace(is); + } - // Handle the end of file. - if (state != IterativeParsingFinishState) - HandleError(state, is); + // Handle the end of file. + if (state != IterativeParsingFinishState) + HandleError(state, is); - return parseResult_; - } + return parseResult_; + } - static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. - internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. - ParseResult parseResult_; + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. + internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. + ParseResult parseResult_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. diff --git a/include/rapidjson/stringbuffer.h b/include/rapidjson/stringbuffer.h index 0e89f95..b8d7968 100644 --- a/include/rapidjson/stringbuffer.h +++ b/include/rapidjson/stringbuffer.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_ @@ -8,35 +28,35 @@ namespace rapidjson { //! Represents an in-memory output stream. /*! - \tparam Encoding Encoding of the stream. - \tparam Allocator type for allocating memory buffer. - \note implements Stream concept + \tparam Encoding Encoding of the stream. + \tparam Allocator type for allocating memory buffer. + \note implements Stream concept */ template struct GenericStringBuffer { - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} + GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} - void Put(Ch c) { *stack_.template Push() = c; } - void Flush() {} + void Put(Ch c) { *stack_.template Push() = c; } + void Flush() {} - void Clear() { stack_.Clear(); } - Ch* Push(size_t count) { return stack_.template Push(count); } - void Pop(size_t count) { stack_.template Pop(count); } + void Clear() { stack_.Clear(); } + Ch* Push(size_t count) { return stack_.template Push(count); } + void Pop(size_t count) { stack_.template Pop(count); } - const Ch* GetString() const { - // Push and pop a null terminator. This is safe. - *stack_.template Push() = '\0'; - stack_.template Pop(1); + const Ch* GetString() const { + // Push and pop a null terminator. This is safe. + *stack_.template Push() = '\0'; + stack_.template Pop(1); - return stack_.template Bottom(); - } + return stack_.template Bottom(); + } - size_t GetSize() const { return stack_.GetSize(); } + size_t GetSize() const { return stack_.GetSize(); } - static const size_t kDefaultCapacity = 256; - mutable internal::Stack stack_; + static const size_t kDefaultCapacity = 256; + mutable internal::Stack stack_; }; //! String buffer with UTF8 encoding @@ -45,7 +65,7 @@ typedef GenericStringBuffer > StringBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { - memset(stream.stack_.Push(n), c, n * sizeof(c)); + memset(stream.stack_.Push(n), c, n * sizeof(c)); } } // namespace rapidjson diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 9d25b27..9fdfde2 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_ @@ -7,7 +27,7 @@ #include "internal/dtoa.h" #include "internal/itoa.h" #include "stringbuffer.h" -#include // placement new +#include // placement new #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH @@ -18,345 +38,345 @@ namespace rapidjson { //! JSON writer /*! Writer implements the concept Handler. - It generates JSON text by events to an output os. + It generates JSON text by events to an output os. - User may programmatically calls the functions of a writer to generate JSON text. + User may programmatically calls the functions of a writer to generate JSON text. - On the other side, a writer can also be passed to objects that generates events, + On the other side, a writer can also be passed to objects that generates events, - for example Reader::Parse() and Document::Accept(). + for example Reader::Parse() and Document::Accept(). - \tparam OutputStream Type of output stream. - \tparam SourceEncoding Encoding of source string. - \tparam TargetEncoding Encoding of output stream. - \tparam Allocator Type of allocator for allocating memory of stack. - \note implements Handler concept + \tparam OutputStream Type of output stream. + \tparam SourceEncoding Encoding of source string. + \tparam TargetEncoding Encoding of output stream. + \tparam Allocator Type of allocator for allocating memory of stack. + \note implements Handler concept */ template, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> > class Writer { public: - typedef typename SourceEncoding::Ch Ch; + typedef typename SourceEncoding::Ch Ch; - //! Constructor - /*! \param os Output stream. - \param allocator User supplied allocator. If it is null, it will create a private one. - \param levelDepth Initial capacity of stack. - */ - Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} + //! Constructor + /*! \param os Output stream. + \param allocator User supplied allocator. If it is null, it will create a private one. + \param levelDepth Initial capacity of stack. + */ + Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} - Writer(Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} + Writer(Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} - //! Reset the writer with a new stream. - /*! - This function reset the writer with a new stream and default settings, - in order to make a Writer object reusable for output multiple JSONs. + //! Reset the writer with a new stream. + /*! + This function reset the writer with a new stream and default settings, + in order to make a Writer object reusable for output multiple JSONs. - \param os New output stream. - \code - Writer writer(os1); - writer.StartObject(); - // ... - writer.EndObject(); + \param os New output stream. + \code + Writer writer(os1); + writer.StartObject(); + // ... + writer.EndObject(); - writer.Reset(os2); - writer.StartObject(); - // ... - writer.EndObject(); - \endcode - */ - void Reset(OutputStream& os) { - os_ = &os; - hasRoot_ = false; - level_stack_.Clear(); - } + writer.Reset(os2); + writer.StartObject(); + // ... + writer.EndObject(); + \endcode + */ + void Reset(OutputStream& os) { + os_ = &os; + hasRoot_ = false; + level_stack_.Clear(); + } - //! Checks whether the output is a complete JSON. - /*! - A complete JSON has a complete root object or array. - */ - bool IsComplete() const { - return hasRoot_ && level_stack_.Empty(); - } + //! Checks whether the output is a complete JSON. + /*! + A complete JSON has a complete root object or array. + */ + bool IsComplete() const { + return hasRoot_ && level_stack_.Empty(); + } - /*!@name Implementation of Handler - \see Handler - */ - //@{ + /*!@name Implementation of Handler + \see Handler + */ + //@{ - bool Null() { Prefix(kNullType); return WriteNull(); } - bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); } - bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } - bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } - bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } - bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); } + bool Null() { Prefix(kNullType); return WriteNull(); } + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); } + bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } + bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } + bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } + bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); } - //! Writes the given \c double value to the stream - /*! - \param d The value to be written. - \return Whether it is succeed. - */ - bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); } + //! Writes the given \c double value to the stream + /*! + \param d The value to be written. + \return Whether it is succeed. + */ + bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); } - bool String(const Ch* str, SizeType length, bool copy = false) { - (void)copy; - Prefix(kStringType); - return WriteString(str, length); - } + bool String(const Ch* str, SizeType length, bool copy = false) { + (void)copy; + Prefix(kStringType); + return WriteString(str, length); + } - bool StartObject() { - Prefix(kObjectType); - new (level_stack_.template Push()) Level(false); - return WriteStartObject(); - } + bool StartObject() { + Prefix(kObjectType); + new (level_stack_.template Push()) Level(false); + return WriteStartObject(); + } - bool EndObject(SizeType memberCount = 0) { - (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); - level_stack_.template Pop(1); - bool ret = WriteEndObject(); - if (level_stack_.Empty()) // end of json text - os_->Flush(); - return ret; - } + bool EndObject(SizeType memberCount = 0) { + (void)memberCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + bool ret = WriteEndObject(); + if (level_stack_.Empty()) // end of json text + os_->Flush(); + return ret; + } - bool StartArray() { - Prefix(kArrayType); - new (level_stack_.template Push()) Level(true); - return WriteStartArray(); - } + bool StartArray() { + Prefix(kArrayType); + new (level_stack_.template Push()) Level(true); + return WriteStartArray(); + } - bool EndArray(SizeType elementCount = 0) { - (void)elementCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); - level_stack_.template Pop(1); - bool ret = WriteEndArray(); - if (level_stack_.Empty()) // end of json text - os_->Flush(); - return ret; - } - //@} + bool EndArray(SizeType elementCount = 0) { + (void)elementCount; + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); + RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); + level_stack_.template Pop(1); + bool ret = WriteEndArray(); + if (level_stack_.Empty()) // end of json text + os_->Flush(); + return ret; + } + //@} - /*! @name Convenience extensions */ - //@{ + /*! @name Convenience extensions */ + //@{ - //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } + //! Simpler but slower overload. + bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - //@} + //@} protected: - //! Information for each nested level - struct Level { - Level(bool inArray_) : valueCount(0), inArray(inArray_) {} - size_t valueCount; //!< number of values in this level - bool inArray; //!< true if in array, otherwise in object - }; + //! Information for each nested level + struct Level { + Level(bool inArray_) : valueCount(0), inArray(inArray_) {} + size_t valueCount; //!< number of values in this level + bool inArray; //!< true if in array, otherwise in object + }; - static const size_t kDefaultLevelDepth = 32; + static const size_t kDefaultLevelDepth = 32; - bool WriteNull() { - os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true; - } + bool WriteNull() { + os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true; + } - bool WriteBool(bool b) { - if (b) { - os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e'); - } - else { - os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e'); - } - return true; - } + bool WriteBool(bool b) { + if (b) { + os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e'); + } + else { + os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e'); + } + return true; + } - bool WriteInt(int i) { - char buffer[11]; - const char* end = internal::i32toa(i, buffer); - for (const char* p = buffer; p != end; ++p) - os_->Put(*p); - return true; - } + bool WriteInt(int i) { + char buffer[11]; + const char* end = internal::i32toa(i, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } - bool WriteUint(unsigned u) { - char buffer[10]; - const char* end = internal::u32toa(u, buffer); - for (const char* p = buffer; p != end; ++p) - os_->Put(*p); - return true; - } + bool WriteUint(unsigned u) { + char buffer[10]; + const char* end = internal::u32toa(u, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } - bool WriteInt64(int64_t i64) { - char buffer[21]; - const char* end = internal::i64toa(i64, buffer); - for (const char* p = buffer; p != end; ++p) - os_->Put(*p); - return true; - } + bool WriteInt64(int64_t i64) { + char buffer[21]; + const char* end = internal::i64toa(i64, buffer); + for (const char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char* end = internal::u64toa(u64, buffer); - for (char* p = buffer; p != end; ++p) - os_->Put(*p); - return true; - } + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* end = internal::u64toa(u64, buffer); + for (char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } - bool WriteDouble(double d) { - char buffer[25]; - char* end = internal::dtoa(d, buffer); - for (char* p = buffer; p != end; ++p) - os_->Put(*p); - return true; - } + bool WriteDouble(double d) { + char buffer[25]; + char* end = internal::dtoa(d, buffer); + for (char* p = buffer; p != end; ++p) + os_->Put(*p); + return true; + } #undef RAPIDJSON_SNPRINTF - bool WriteString(const Ch* str, SizeType length) { - static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - static const char escape[256] = { + bool WriteString(const Ch* str, SizeType length) { + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - //0 1 2 3 4 5 6 7 8 9 A B C D E F - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 - 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 - 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 - Z16, Z16, // 30~4F - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 - Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 + Z16, Z16, // 30~4F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF #undef Z16 - }; + }; - os_->Put('\"'); - GenericStringStream is(str); - while (is.Tell() < length) { - const Ch c = is.Peek(); - if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { - // Unicode escaping - unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) - return false; - os_->Put('\\'); - os_->Put('u'); - if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { - os_->Put(hexDigits[(codepoint >> 12) & 15]); - os_->Put(hexDigits[(codepoint >> 8) & 15]); - os_->Put(hexDigits[(codepoint >> 4) & 15]); - os_->Put(hexDigits[(codepoint ) & 15]); - } - else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) { - // Surrogate pair - unsigned s = codepoint - 0x010000; - unsigned lead = (s >> 10) + 0xD800; - unsigned trail = (s & 0x3FF) + 0xDC00; - os_->Put(hexDigits[(lead >> 12) & 15]); - os_->Put(hexDigits[(lead >> 8) & 15]); - os_->Put(hexDigits[(lead >> 4) & 15]); - os_->Put(hexDigits[(lead ) & 15]); - os_->Put('\\'); - os_->Put('u'); - os_->Put(hexDigits[(trail >> 12) & 15]); - os_->Put(hexDigits[(trail >> 8) & 15]); - os_->Put(hexDigits[(trail >> 4) & 15]); - os_->Put(hexDigits[(trail ) & 15]); - } - else - return false; // invalid code point - } - else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { - is.Take(); - os_->Put('\\'); - os_->Put(escape[(unsigned char)c]); - if (escape[(unsigned char)c] == 'u') { - os_->Put('0'); - os_->Put('0'); - os_->Put(hexDigits[(unsigned char)c >> 4]); - os_->Put(hexDigits[(unsigned char)c & 0xF]); - } - } - else - Transcoder::Transcode(is, *os_); - } - os_->Put('\"'); - return true; - } + os_->Put('\"'); + GenericStringStream is(str); + while (is.Tell() < length) { + const Ch c = is.Peek(); + if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { + // Unicode escaping + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + os_->Put('\\'); + os_->Put('u'); + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { + os_->Put(hexDigits[(codepoint >> 12) & 15]); + os_->Put(hexDigits[(codepoint >> 8) & 15]); + os_->Put(hexDigits[(codepoint >> 4) & 15]); + os_->Put(hexDigits[(codepoint ) & 15]); + } + else if (codepoint >= 0x010000 && codepoint <= 0x10FFFF) { + // Surrogate pair + unsigned s = codepoint - 0x010000; + unsigned lead = (s >> 10) + 0xD800; + unsigned trail = (s & 0x3FF) + 0xDC00; + os_->Put(hexDigits[(lead >> 12) & 15]); + os_->Put(hexDigits[(lead >> 8) & 15]); + os_->Put(hexDigits[(lead >> 4) & 15]); + os_->Put(hexDigits[(lead ) & 15]); + os_->Put('\\'); + os_->Put('u'); + os_->Put(hexDigits[(trail >> 12) & 15]); + os_->Put(hexDigits[(trail >> 8) & 15]); + os_->Put(hexDigits[(trail >> 4) & 15]); + os_->Put(hexDigits[(trail ) & 15]); + } + else + return false; // invalid code point + } + else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { + is.Take(); + os_->Put('\\'); + os_->Put(escape[(unsigned char)c]); + if (escape[(unsigned char)c] == 'u') { + os_->Put('0'); + os_->Put('0'); + os_->Put(hexDigits[(unsigned char)c >> 4]); + os_->Put(hexDigits[(unsigned char)c & 0xF]); + } + } + else + Transcoder::Transcode(is, *os_); + } + os_->Put('\"'); + return true; + } - bool WriteStartObject() { os_->Put('{'); return true; } - bool WriteEndObject() { os_->Put('}'); return true; } - bool WriteStartArray() { os_->Put('['); return true; } - bool WriteEndArray() { os_->Put(']'); return true; } + bool WriteStartObject() { os_->Put('{'); return true; } + bool WriteEndObject() { os_->Put('}'); return true; } + bool WriteStartArray() { os_->Put('['); return true; } + bool WriteEndArray() { os_->Put(']'); return true; } - void Prefix(Type type) { - (void)type; - if (level_stack_.GetSize() != 0) { // this value is not at root - Level* level = level_stack_.template Top(); - if (level->valueCount > 0) { - if (level->inArray) - os_->Put(','); // add comma if it is not the first element in array - else // in object - os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); - } - if (!level->inArray && level->valueCount % 2 == 0) - RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name - level->valueCount++; - } - else { - RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); - RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. - hasRoot_ = true; - } - } + void Prefix(Type type) { + (void)type; + if (level_stack_.GetSize() != 0) { // this value is not at root + Level* level = level_stack_.template Top(); + if (level->valueCount > 0) { + if (level->inArray) + os_->Put(','); // add comma if it is not the first element in array + else // in object + os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); + } + if (!level->inArray && level->valueCount % 2 == 0) + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name + level->valueCount++; + } + else { + RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType); + RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. + hasRoot_ = true; + } + } - OutputStream* os_; - internal::Stack level_stack_; - bool hasRoot_; + OutputStream* os_; + internal::Stack level_stack_; + bool hasRoot_; private: - // Prohibit copy constructor & assignment operator. - Writer(const Writer&); - Writer& operator=(const Writer&); + // Prohibit copy constructor & assignment operator. + Writer(const Writer&); + Writer& operator=(const Writer&); }; // Full specialization for StringStream to prevent memory copying template<> inline bool Writer::WriteInt(int i) { - char *buffer = os_->Push(11); - const char* end = internal::i32toa(i, buffer); - os_->Pop(11 - (end - buffer)); - return true; + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(11 - (end - buffer)); + return true; } template<> inline bool Writer::WriteUint(unsigned u) { - char *buffer = os_->Push(10); - const char* end = internal::u32toa(u, buffer); - os_->Pop(10 - (end - buffer)); - return true; + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(10 - (end - buffer)); + return true; } template<> inline bool Writer::WriteInt64(int64_t i64) { - char *buffer = os_->Push(21); - const char* end = internal::i64toa(i64, buffer); - os_->Pop(21 - (end - buffer)); - return true; + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(21 - (end - buffer)); + return true; } template<> inline bool Writer::WriteUint64(uint64_t u) { - char *buffer = os_->Push(20); - const char* end = internal::u64toa(u, buffer); - os_->Pop(20 - (end - buffer)); - return true; + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(20 - (end - buffer)); + return true; } template<> inline bool Writer::WriteDouble(double d) { - char *buffer = os_->Push(25); - char* end = internal::dtoa(d, buffer); - os_->Pop(25 - (end - buffer)); - return true; + char *buffer = os_->Push(25); + char* end = internal::dtoa(d, buffer); + os_->Pop(25 - (end - buffer)); + return true; } } // namespace rapidjson diff --git a/test/perftest/jsoncpptest.cpp b/test/perftest/jsoncpptest.cpp index 1f5add4..2ce5b8a 100644 --- a/test/perftest/jsoncpptest.cpp +++ b/test/perftest/jsoncpptest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "perftest.h" #if TEST_JSONCPP @@ -10,48 +30,48 @@ using namespace Json; class JsonCpp : public PerfTest { public: - virtual void SetUp() { - PerfTest::SetUp(); - Reader reader; - ASSERT_TRUE(reader.parse(json_, root_)); - } + virtual void SetUp() { + PerfTest::SetUp(); + Reader reader; + ASSERT_TRUE(reader.parse(json_, root_)); + } protected: - Value root_; + Value root_; }; TEST_F(JsonCpp, ReaderParse) { - for (int i = 0; i < kTrialCount; i++) { - Value root; - Reader reader; - ASSERT_TRUE(reader.parse(json_, root)); - } + for (int i = 0; i < kTrialCount; i++) { + Value root; + Reader reader; + ASSERT_TRUE(reader.parse(json_, root)); + } } TEST_F(JsonCpp, FastWriter) { - for (int i = 0; i < kTrialCount; i++) { - FastWriter writer; - std::string str = writer.write(root_); - //if (i == 0) - // std::cout << str.length() << std::endl; - } + for (int i = 0; i < kTrialCount; i++) { + FastWriter writer; + std::string str = writer.write(root_); + //if (i == 0) + // std::cout << str.length() << std::endl; + } } TEST_F(JsonCpp, StyledWriter) { - for (int i = 0; i < kTrialCount; i++) { - StyledWriter writer; - std::string str = writer.write(root_); - //if (i == 0) - // std::cout << str.length() << std::endl; - } + for (int i = 0; i < kTrialCount; i++) { + StyledWriter writer; + std::string str = writer.write(root_); + //if (i == 0) + // std::cout << str.length() << std::endl; + } } TEST_F(JsonCpp, Whitespace) { - for (int i = 0; i < kTrialCount; i++) { - Value root; - Reader reader; - ASSERT_TRUE(reader.parse(whitespace_, root)); - } + for (int i = 0; i < kTrialCount; i++) { + Value root; + Reader reader; + ASSERT_TRUE(reader.parse(whitespace_, root)); + } } #endif // TEST_JSONCPP diff --git a/test/perftest/misctest.cpp b/test/perftest/misctest.cpp index dfa50f8..fe2d947 100644 --- a/test/perftest/misctest.cpp +++ b/test/perftest/misctest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "perftest.h" #if TEST_MISC @@ -43,202 +63,202 @@ class Misc : public PerfTest { #define UTF8_REJECT 12 static const unsigned char utf8d[] = { - // The first part of the table maps bytes to character classes that - // to reduce the size of the transition table and create bitmasks. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + // The first part of the table maps bytes to character classes that + // to reduce the size of the transition table and create bitmasks. + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - // The second part is a transition table that maps a combination - // of a state of the automaton and a character class to a state. - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, - 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, - 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, - 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, - 12,36,12,12,12,12,12,12,12,12,12,12, + // The second part is a transition table that maps a combination + // of a state of the automaton and a character class to a state. + 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, + 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, + 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, + 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, + 12,36,12,12,12,12,12,12,12,12,12,12, }; static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) { - unsigned type = utf8d[byte]; + unsigned type = utf8d[byte]; - *codep = (*state != UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); - *state = utf8d[256 + *state + type]; - return *state; + *state = utf8d[256 + *state + type]; + return *state; } static bool IsUTF8(unsigned char* s) { - unsigned codepoint, state = 0; + unsigned codepoint, state = 0; - while (*s) - decode(&state, &codepoint, *s++); + while (*s) + decode(&state, &codepoint, *s++); - return state == UTF8_ACCEPT; + return state == UTF8_ACCEPT; } TEST_F(Misc, Hoehrmann_IsUTF8) { - for (size_t i = 0; i < kTrialCount; i++) { - EXPECT_TRUE(IsUTF8((unsigned char*)json_)); - } + for (size_t i = 0; i < kTrialCount; i++) { + EXPECT_TRUE(IsUTF8((unsigned char*)json_)); + } } //////////////////////////////////////////////////////////////////////////////// // CountDecimalDigit: Count number of decimal places inline unsigned CountDecimalDigit_naive(unsigned n) { - unsigned count = 1; - while (n >= 10) { - n /= 10; - count++; - } - return count; + unsigned count = 1; + while (n >= 10) { + n /= 10; + count++; + } + return count; } inline unsigned CountDecimalDigit_enroll4(unsigned n) { - unsigned count = 1; - while (n >= 10000) { - n /= 10000u; - count += 4; - } - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - return count + 3; + unsigned count = 1; + while (n >= 10000) { + n /= 10000u; + count += 4; + } + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + return count + 3; } inline unsigned CountDecimalDigit64_enroll4(uint64_t n) { - unsigned count = 1; - while (n >= 10000) { - n /= 10000u; - count += 4; - } - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - return count + 3; + unsigned count = 1; + while (n >= 10000) { + n /= 10000u; + count += 4; + } + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + return count + 3; } inline unsigned CountDecimalDigit_fast(unsigned n) { - static const uint32_t powers_of_10[] = { - 0, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000 - }; + static const uint32_t powers_of_10[] = { + 0, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 + }; #if defined(_M_IX86) || defined(_M_X64) - unsigned long i = 0; - _BitScanReverse(&i, n | 1); - uint32_t t = (i + 1) * 1233 >> 12; + unsigned long i = 0; + _BitScanReverse(&i, n | 1); + uint32_t t = (i + 1) * 1233 >> 12; #elif defined(__GNUC__) - uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; + uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; #else #error #endif - return t - (n < powers_of_10[t]) + 1; + return t - (n < powers_of_10[t]) + 1; } inline unsigned CountDecimalDigit64_fast(uint64_t n) { - static const uint64_t powers_of_10[] = { - 0, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, - 10000000000000000, - 100000000000000000, - 1000000000000000000, - 10000000000000000000U - }; + static const uint64_t powers_of_10[] = { + 0, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U + }; #if defined(_M_IX86) - uint64_t m = n | 1; - unsigned long i = 0; - if (_BitScanReverse(&i, m >> 32)) - i += 32; - else - _BitScanReverse(&i, m & 0xFFFFFFFF); - uint32_t t = (i + 1) * 1233 >> 12; + uint64_t m = n | 1; + unsigned long i = 0; + if (_BitScanReverse(&i, m >> 32)) + i += 32; + else + _BitScanReverse(&i, m & 0xFFFFFFFF); + uint32_t t = (i + 1) * 1233 >> 12; #elif defined(_M_X64) - unsigned long i = 0; - _BitScanReverse64(&i, n | 1); - uint32_t t = (i + 1) * 1233 >> 12; + unsigned long i = 0; + _BitScanReverse64(&i, n | 1); + uint32_t t = (i + 1) * 1233 >> 12; #elif defined(__GNUC__) - uint32_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; + uint32_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; #else #error #endif - return t - (n < powers_of_10[t]) + 1; + return t - (n < powers_of_10[t]) + 1; } #if 0 // Exhaustive, very slow TEST_F(Misc, CountDecimalDigit_Verify) { - unsigned i = 0; - do { - if (i % (65536 * 256) == 0) - printf("%u\n", i); - ASSERT_EQ(CountDecimalDigit_enroll4(i), CountDecimalDigit_fast(i)); - i++; - } while (i != 0); + unsigned i = 0; + do { + if (i % (65536 * 256) == 0) + printf("%u\n", i); + ASSERT_EQ(CountDecimalDigit_enroll4(i), CountDecimalDigit_fast(i)); + i++; + } while (i != 0); } static const unsigned kDigits10Trial = 1000000000u; TEST_F(Misc, CountDecimalDigit_naive) { - unsigned sum = 0; - for (unsigned i = 0; i < kDigits10Trial; i++) - sum += CountDecimalDigit_naive(i); - printf("%u\n", sum); + unsigned sum = 0; + for (unsigned i = 0; i < kDigits10Trial; i++) + sum += CountDecimalDigit_naive(i); + printf("%u\n", sum); } TEST_F(Misc, CountDecimalDigit_enroll4) { - unsigned sum = 0; - for (unsigned i = 0; i < kDigits10Trial; i++) - sum += CountDecimalDigit_enroll4(i); - printf("%u\n", sum); + unsigned sum = 0; + for (unsigned i = 0; i < kDigits10Trial; i++) + sum += CountDecimalDigit_enroll4(i); + printf("%u\n", sum); } TEST_F(Misc, CountDecimalDigit_fast) { - unsigned sum = 0; - for (unsigned i = 0; i < kDigits10Trial; i++) - sum += CountDecimalDigit_fast(i); - printf("%u\n", sum); + unsigned sum = 0; + for (unsigned i = 0; i < kDigits10Trial; i++) + sum += CountDecimalDigit_fast(i); + printf("%u\n", sum); } #endif TEST_F(Misc, CountDecimalDigit64_VerifyFast) { - uint64_t i = 1, j; - do { - //printf("%" PRIu64 "\n", i); - ASSERT_EQ(CountDecimalDigit64_enroll4(i), CountDecimalDigit64_fast(i)); - j = i; - i *= 3; - } while (j < i); + uint64_t i = 1, j; + do { + //printf("%" PRIu64 "\n", i); + ASSERT_EQ(CountDecimalDigit64_enroll4(i), CountDecimalDigit64_fast(i)); + j = i; + i *= 3; + } while (j < i); } //////////////////////////////////////////////////////////////////////////////// @@ -246,109 +266,109 @@ TEST_F(Misc, CountDecimalDigit64_VerifyFast) { // https://gist.github.com/anonymous/7179097 static const int randval[] ={ - 936116, 369532, 453755, -72860, 209713, 268347, 435278, -360266, -416287, -182064, - -644712, 944969, 640463, -366588, 471577, -69401, -744294, -505829, 923883, 831785, - -601136, -636767, -437054, 591718, 100758, 231907, -719038, 973540, -605220, 506659, - -871653, 462533, 764843, -919138, 404305, -630931, -288711, -751454, -173726, -718208, - 432689, -281157, 360737, 659827, 19174, -376450, 769984, -858198, 439127, 734703, - -683426, 7, 386135, 186997, -643900, -744422, -604708, -629545, 42313, -933592, - -635566, 182308, 439024, -367219, -73924, -516649, 421935, -470515, 413507, -78952, - -427917, -561158, 737176, 94538, 572322, 405217, 709266, -357278, -908099, -425447, - 601119, 750712, -862285, -177869, 900102, 384877, 157859, -641680, 503738, -702558, - 278225, 463290, 268378, -212840, 580090, 347346, -473985, -950968, -114547, -839893, - -738032, -789424, 409540, 493495, 432099, 119755, 905004, -174834, 338266, 234298, - 74641, -965136, -754593, 685273, 466924, 920560, 385062, 796402, -67229, 994864, - 376974, 299869, -647540, -128724, 469890, -163167, -547803, -743363, 486463, -621028, - 612288, 27459, -514224, 126342, -66612, 803409, -777155, -336453, -284002, 472451, - 342390, -163630, 908356, -456147, -825607, 268092, -974715, 287227, 227890, -524101, - 616370, -782456, 922098, -624001, -813690, 171605, -192962, 796151, 707183, -95696, - -23163, -721260, 508892, 430715, 791331, 482048, -996102, 863274, 275406, -8279, - -556239, -902076, 268647, -818565, 260069, -798232, -172924, -566311, -806503, -885992, - 813969, -78468, 956632, 304288, 494867, -508784, 381751, 151264, 762953, 76352, - 594902, 375424, 271700, -743062, 390176, 924237, 772574, 676610, 435752, -153847, - 3959, -971937, -294181, -538049, -344620, -170136, 19120, -703157, 868152, -657961, - -818631, 219015, -872729, -940001, -956570, 880727, -345910, 942913, -942271, -788115, - 225294, 701108, -517736, -416071, 281940, 488730, 942698, 711494, 838382, -892302, - -533028, 103052, 528823, 901515, 949577, 159364, 718227, -241814, -733661, -462928, - -495829, 165170, 513580, -629188, -509571, -459083, 198437, 77198, -644612, 811276, - -422298, -860842, -52584, 920369, 686424, -530667, -243476, 49763, 345866, -411960, - -114863, 470810, -302860, 683007, -509080, 2, -174981, -772163, -48697, 447770, - -268246, 213268, 269215, 78810, -236340, -639140, -864323, 505113, -986569, -325215, - 541859, 163070, -819998, -645161, -583336, 573414, 696417, -132375, 3, -294501, - 320435, 682591, 840008, 351740, 426951, 609354, 898154, -943254, 227321, -859793, - -727993, 44137, -497965, -782239, 14955, -746080, -243366, 9837, -233083, 606507, - -995864, -615287, -994307, 602715, 770771, -315040, 610860, 446102, -307120, 710728, - -590392, -230474, -762625, -637525, 134963, -202700, -766902, -985541, 218163, 682009, - 926051, 525156, -61195, 403211, -810098, 245539, -431733, 179998, -806533, 745943, - 447597, 131973, -187130, 826019, 286107, -937230, -577419, 20254, 681802, -340500, - 323080, 266283, -667617, 309656, 416386, 611863, 759991, -534257, 523112, -634892, - -169913, -204905, -909867, -882185, -944908, 741811, -717675, 967007, -317396, 407230, - -412805, 792905, 994873, 744793, -456797, 713493, 355232, 116900, -945199, 880539, - 342505, -580824, -262273, 982968, -349497, -735488, 311767, -455191, 570918, 389734, - -958386, 10262, -99267, 155481, 304210, 204724, 704367, -144893, -233664, -671441, - 896849, 408613, 762236, 322697, 981321, 688476, 13663, -970704, -379507, 896412, - 977084, 348869, 875948, 341348, 318710, 512081, 6163, 669044, 833295, 811883, - 708756, -802534, -536057, 608413, -389625, -694603, 541106, -110037, 720322, -540581, - 645420, 32980, 62442, 510157, -981870, -87093, -325960, -500494, -718291, -67889, - 991501, 374804, 769026, -978869, 294747, 714623, 413327, -199164, 671368, 804789, - -362507, 798196, -170790, -568895, -869379, 62020, -316693, -837793, 644994, -39341, - -417504, -243068, -957756, 99072, 622234, -739992, 225668, 8863, -505910, 82483, - -559244, 241572, 1315, -36175, -54990, 376813, -11, 162647, -688204, -486163, - -54934, -197470, 744223, -762707, 732540, 996618, 351561, -445933, -898491, 486531, - 456151, 15276, 290186, -817110, -52995, 313046, -452533, -96267, 94470, -500176, - -818026, -398071, -810548, -143325, -819741, 1338, -897676, -101577, -855445, 37309, - 285742, 953804, -777927, -926962, -811217, -936744, -952245, -802300, -490188, -964953, - -552279, 329142, -570048, -505756, 682898, -381089, -14352, 175138, 152390, -582268, - -485137, 717035, 805329, 239572, -730409, 209643, -184403, -385864, 675086, 819648, - 629058, -527109, -488666, -171981, 532788, 552441, 174666, 984921, 766514, 758787, - 716309, 338801, -978004, -412163, 876079, -734212, 789557, -160491, -522719, 56644, - -991, -286038, -53983, 663740, 809812, 919889, -717502, -137704, 220511, 184396, - -825740, -588447, 430870, 124309, 135956, 558662, -307087, -788055, -451328, 812260, - 931601, 324347, -482989, -117858, -278861, 189068, -172774, 929057, 293787, 198161, - -342386, -47173, 906555, -759955, -12779, 777604, -97869, 899320, 927486, -25284, - -848550, 259450, -485856, -17820, 88, 171400, 235492, -326783, -340793, 886886, - 112428, -246280, 5979, 648444, -114982, 991013, -56489, -9497, 419706, 632820, - -341664, 393926, -848977, -22538, 257307, 773731, -905319, 491153, 734883, -868212, - -951053, 644458, -580758, 764735, 584316, 297077, 28852, -397710, -953669, 201772, - 879050, -198237, -588468, 448102, -116837, 770007, -231812, 642906, -582166, -885828, - 9, 305082, -996577, 303559, 75008, -772956, -447960, 599825, -295552, 870739, - -386278, -950300, 485359, -457081, 629461, -850276, 550496, -451755, -620841, -11766, - -950137, 832337, 28711, -273398, -507197, 91921, -271360, -705991, -753220, -388968, - 967945, 340434, -320883, -662793, -554617, -574568, 477946, -6148, -129519, 689217, - 920020, -656315, -974523, -212525, 80921, -612532, 645096, 545655, 655713, -591631, - -307385, -816688, -618823, -113713, 526430, 673063, 735916, -809095, -850417, 639004, - 432281, -388185, 270708, 860146, -39902, -786157, -258180, -246169, -966720, -264957, - 548072, -306010, -57367, -635665, 933824, 70553, -989936, -488741, 72411, -452509, - 529831, 956277, 449019, -577850, -360986, -803418, 48833, 296073, 203430, 609591, - 715483, 470964, 658106, -718254, -96424, 790163, 334739, 181070, -373578, 5, - -435088, 329841, 330939, -256602, 394355, 912412, 231910, 927278, -661933, 788539, - -769664, -893274, -96856, 298205, 901043, -608122, -527430, 183618, -553963, -35246, - -393924, 948832, -483198, 594501, 35460, -407007, 93494, -336881, -634072, 984205, - -812161, 944664, -31062, 753872, 823933, -69566, 50445, 290147, 85134, 34706, - 551902, 405202, -991246, -84642, 154341, 316432, -695101, -651588, -5030, 137564, - -294665, 332541, 528307, -90572, -344923, 523766, -758498, -968047, 339028, 494578, - 593129, -725773, 31834, -718406, -208638, 159665, -2043, 673344, -442767, 75816, - 755442, 769257, -158730, -410272, 691688, 589550, -878398, -184121, 460679, 346312, - 294163, -544602, 653308, 254167, -276979, 52073, -892684, 887653, -41222, 983065, - -68258, -408799, -99069, -674069, -863635, -32890, 622757, -743862, 40872, -4837, - -967228, 522370, -903951, -818669, 524459, 514702, 925801, 20007, -299229, 579348, - 626021, 430089, 348139, -562692, -607728, -130606, -928451, -424793, -458647, -448892, - -312230, 143337, 109746, 880042, -339658, -785614, 938995, 540916, 118429, 661351, - -402967, 404729, -40918, -976535, 743230, 713110, 440182, -381314, -499252, 74613, - 193652, 912717, 491323, 583633, 324691, 459397, 281253, 195540, -2764, -888651, - 892449, 132663, -478373, -430002, -314551, 527826, 247165, 557966, 554778, 481531, - -946634, 431685, -769059, -348371, 174046, 184597, -354867, 584422, 227390, -850397, - -542924, -849093, -737769, 325359, 736314, 269101, 767940, 674809, 81413, -447458, - 445076, 189072, 906218, 502688, -718476, -863827, -731381, 100660, 623249, 710008, - 572060, 922203, 685740, 55096, 263394, -243695, -353910, -516788, 388471, 455165, - 844103, -643772, 363976, 268875, -899450, 104470, 104029, -238874, -274659, 732969, - -676443, 953291, -916289, -861849, -242344, 958083, -479593, -970395, 799831, 277841, - -243236, -283462, -201510, 166263, -259105, -575706, 878926, 891064, 895297, 655262, - -34807, -809833, -89281, 342585, 554920, 1, 902141, -333425, 139703, 852318, - -618438, 329498, -932596, -692836, -513372, 733656, -523411, 85779, 500478, -682697, - -502836, 138776, 156341, -420037, -557964, -556378, 710993, -50383, -877159, 916334, - 132996, 583516, -603392, -111615, -12288, -780214, 476780, 123327, 137607, 519956, - 745837, 17358, -158581, -53490 + 936116, 369532, 453755, -72860, 209713, 268347, 435278, -360266, -416287, -182064, + -644712, 944969, 640463, -366588, 471577, -69401, -744294, -505829, 923883, 831785, + -601136, -636767, -437054, 591718, 100758, 231907, -719038, 973540, -605220, 506659, + -871653, 462533, 764843, -919138, 404305, -630931, -288711, -751454, -173726, -718208, + 432689, -281157, 360737, 659827, 19174, -376450, 769984, -858198, 439127, 734703, + -683426, 7, 386135, 186997, -643900, -744422, -604708, -629545, 42313, -933592, + -635566, 182308, 439024, -367219, -73924, -516649, 421935, -470515, 413507, -78952, + -427917, -561158, 737176, 94538, 572322, 405217, 709266, -357278, -908099, -425447, + 601119, 750712, -862285, -177869, 900102, 384877, 157859, -641680, 503738, -702558, + 278225, 463290, 268378, -212840, 580090, 347346, -473985, -950968, -114547, -839893, + -738032, -789424, 409540, 493495, 432099, 119755, 905004, -174834, 338266, 234298, + 74641, -965136, -754593, 685273, 466924, 920560, 385062, 796402, -67229, 994864, + 376974, 299869, -647540, -128724, 469890, -163167, -547803, -743363, 486463, -621028, + 612288, 27459, -514224, 126342, -66612, 803409, -777155, -336453, -284002, 472451, + 342390, -163630, 908356, -456147, -825607, 268092, -974715, 287227, 227890, -524101, + 616370, -782456, 922098, -624001, -813690, 171605, -192962, 796151, 707183, -95696, + -23163, -721260, 508892, 430715, 791331, 482048, -996102, 863274, 275406, -8279, + -556239, -902076, 268647, -818565, 260069, -798232, -172924, -566311, -806503, -885992, + 813969, -78468, 956632, 304288, 494867, -508784, 381751, 151264, 762953, 76352, + 594902, 375424, 271700, -743062, 390176, 924237, 772574, 676610, 435752, -153847, + 3959, -971937, -294181, -538049, -344620, -170136, 19120, -703157, 868152, -657961, + -818631, 219015, -872729, -940001, -956570, 880727, -345910, 942913, -942271, -788115, + 225294, 701108, -517736, -416071, 281940, 488730, 942698, 711494, 838382, -892302, + -533028, 103052, 528823, 901515, 949577, 159364, 718227, -241814, -733661, -462928, + -495829, 165170, 513580, -629188, -509571, -459083, 198437, 77198, -644612, 811276, + -422298, -860842, -52584, 920369, 686424, -530667, -243476, 49763, 345866, -411960, + -114863, 470810, -302860, 683007, -509080, 2, -174981, -772163, -48697, 447770, + -268246, 213268, 269215, 78810, -236340, -639140, -864323, 505113, -986569, -325215, + 541859, 163070, -819998, -645161, -583336, 573414, 696417, -132375, 3, -294501, + 320435, 682591, 840008, 351740, 426951, 609354, 898154, -943254, 227321, -859793, + -727993, 44137, -497965, -782239, 14955, -746080, -243366, 9837, -233083, 606507, + -995864, -615287, -994307, 602715, 770771, -315040, 610860, 446102, -307120, 710728, + -590392, -230474, -762625, -637525, 134963, -202700, -766902, -985541, 218163, 682009, + 926051, 525156, -61195, 403211, -810098, 245539, -431733, 179998, -806533, 745943, + 447597, 131973, -187130, 826019, 286107, -937230, -577419, 20254, 681802, -340500, + 323080, 266283, -667617, 309656, 416386, 611863, 759991, -534257, 523112, -634892, + -169913, -204905, -909867, -882185, -944908, 741811, -717675, 967007, -317396, 407230, + -412805, 792905, 994873, 744793, -456797, 713493, 355232, 116900, -945199, 880539, + 342505, -580824, -262273, 982968, -349497, -735488, 311767, -455191, 570918, 389734, + -958386, 10262, -99267, 155481, 304210, 204724, 704367, -144893, -233664, -671441, + 896849, 408613, 762236, 322697, 981321, 688476, 13663, -970704, -379507, 896412, + 977084, 348869, 875948, 341348, 318710, 512081, 6163, 669044, 833295, 811883, + 708756, -802534, -536057, 608413, -389625, -694603, 541106, -110037, 720322, -540581, + 645420, 32980, 62442, 510157, -981870, -87093, -325960, -500494, -718291, -67889, + 991501, 374804, 769026, -978869, 294747, 714623, 413327, -199164, 671368, 804789, + -362507, 798196, -170790, -568895, -869379, 62020, -316693, -837793, 644994, -39341, + -417504, -243068, -957756, 99072, 622234, -739992, 225668, 8863, -505910, 82483, + -559244, 241572, 1315, -36175, -54990, 376813, -11, 162647, -688204, -486163, + -54934, -197470, 744223, -762707, 732540, 996618, 351561, -445933, -898491, 486531, + 456151, 15276, 290186, -817110, -52995, 313046, -452533, -96267, 94470, -500176, + -818026, -398071, -810548, -143325, -819741, 1338, -897676, -101577, -855445, 37309, + 285742, 953804, -777927, -926962, -811217, -936744, -952245, -802300, -490188, -964953, + -552279, 329142, -570048, -505756, 682898, -381089, -14352, 175138, 152390, -582268, + -485137, 717035, 805329, 239572, -730409, 209643, -184403, -385864, 675086, 819648, + 629058, -527109, -488666, -171981, 532788, 552441, 174666, 984921, 766514, 758787, + 716309, 338801, -978004, -412163, 876079, -734212, 789557, -160491, -522719, 56644, + -991, -286038, -53983, 663740, 809812, 919889, -717502, -137704, 220511, 184396, + -825740, -588447, 430870, 124309, 135956, 558662, -307087, -788055, -451328, 812260, + 931601, 324347, -482989, -117858, -278861, 189068, -172774, 929057, 293787, 198161, + -342386, -47173, 906555, -759955, -12779, 777604, -97869, 899320, 927486, -25284, + -848550, 259450, -485856, -17820, 88, 171400, 235492, -326783, -340793, 886886, + 112428, -246280, 5979, 648444, -114982, 991013, -56489, -9497, 419706, 632820, + -341664, 393926, -848977, -22538, 257307, 773731, -905319, 491153, 734883, -868212, + -951053, 644458, -580758, 764735, 584316, 297077, 28852, -397710, -953669, 201772, + 879050, -198237, -588468, 448102, -116837, 770007, -231812, 642906, -582166, -885828, + 9, 305082, -996577, 303559, 75008, -772956, -447960, 599825, -295552, 870739, + -386278, -950300, 485359, -457081, 629461, -850276, 550496, -451755, -620841, -11766, + -950137, 832337, 28711, -273398, -507197, 91921, -271360, -705991, -753220, -388968, + 967945, 340434, -320883, -662793, -554617, -574568, 477946, -6148, -129519, 689217, + 920020, -656315, -974523, -212525, 80921, -612532, 645096, 545655, 655713, -591631, + -307385, -816688, -618823, -113713, 526430, 673063, 735916, -809095, -850417, 639004, + 432281, -388185, 270708, 860146, -39902, -786157, -258180, -246169, -966720, -264957, + 548072, -306010, -57367, -635665, 933824, 70553, -989936, -488741, 72411, -452509, + 529831, 956277, 449019, -577850, -360986, -803418, 48833, 296073, 203430, 609591, + 715483, 470964, 658106, -718254, -96424, 790163, 334739, 181070, -373578, 5, + -435088, 329841, 330939, -256602, 394355, 912412, 231910, 927278, -661933, 788539, + -769664, -893274, -96856, 298205, 901043, -608122, -527430, 183618, -553963, -35246, + -393924, 948832, -483198, 594501, 35460, -407007, 93494, -336881, -634072, 984205, + -812161, 944664, -31062, 753872, 823933, -69566, 50445, 290147, 85134, 34706, + 551902, 405202, -991246, -84642, 154341, 316432, -695101, -651588, -5030, 137564, + -294665, 332541, 528307, -90572, -344923, 523766, -758498, -968047, 339028, 494578, + 593129, -725773, 31834, -718406, -208638, 159665, -2043, 673344, -442767, 75816, + 755442, 769257, -158730, -410272, 691688, 589550, -878398, -184121, 460679, 346312, + 294163, -544602, 653308, 254167, -276979, 52073, -892684, 887653, -41222, 983065, + -68258, -408799, -99069, -674069, -863635, -32890, 622757, -743862, 40872, -4837, + -967228, 522370, -903951, -818669, 524459, 514702, 925801, 20007, -299229, 579348, + 626021, 430089, 348139, -562692, -607728, -130606, -928451, -424793, -458647, -448892, + -312230, 143337, 109746, 880042, -339658, -785614, 938995, 540916, 118429, 661351, + -402967, 404729, -40918, -976535, 743230, 713110, 440182, -381314, -499252, 74613, + 193652, 912717, 491323, 583633, 324691, 459397, 281253, 195540, -2764, -888651, + 892449, 132663, -478373, -430002, -314551, 527826, 247165, 557966, 554778, 481531, + -946634, 431685, -769059, -348371, 174046, 184597, -354867, 584422, 227390, -850397, + -542924, -849093, -737769, 325359, 736314, 269101, 767940, 674809, 81413, -447458, + 445076, 189072, 906218, 502688, -718476, -863827, -731381, 100660, 623249, 710008, + 572060, 922203, 685740, 55096, 263394, -243695, -353910, -516788, 388471, 455165, + 844103, -643772, 363976, 268875, -899450, 104470, 104029, -238874, -274659, 732969, + -676443, 953291, -916289, -861849, -242344, 958083, -479593, -970395, 799831, 277841, + -243236, -283462, -201510, 166263, -259105, -575706, 878926, 891064, 895297, 655262, + -34807, -809833, -89281, 342585, 554920, 1, 902141, -333425, 139703, 852318, + -618438, 329498, -932596, -692836, -513372, 733656, -523411, 85779, 500478, -682697, + -502836, 138776, 156341, -420037, -557964, -556378, 710993, -50383, -877159, 916334, + 132996, 583516, -603392, -111615, -12288, -780214, 476780, 123327, 137607, 519956, + 745837, 17358, -158581, -53490 }; static const size_t randvalCount = sizeof(randval) / sizeof(randval[0]); static const size_t kItoaTrialCount = 10000; @@ -367,537 +387,537 @@ static const char digits[201] = template class Writer1 { public: - Writer1() : os_() {} - Writer1(OutputStream& os) : os_(&os) {} + Writer1() : os_() {} + Writer1(OutputStream& os) : os_(&os) {} - void Reset(OutputStream& os) { - os_ = &os; - } + void Reset(OutputStream& os) { + os_ = &os; + } - bool WriteInt(int i) { - if (i < 0) { - os_->Put('-'); - i = -i; - } - return WriteUint((unsigned)i); - } + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } - bool WriteUint(unsigned u) { - char buffer[10]; - char *p = buffer; - do { - *p++ = char(u % 10) + '0'; - u /= 10; - } while (u > 0); + bool WriteUint(unsigned u) { + char buffer[10]; + char *p = buffer; + do { + *p++ = char(u % 10) + '0'; + u /= 10; + } while (u > 0); - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } - bool WriteInt64(int64_t i64) { - if (i64 < 0) { - os_->Put('-'); - i64 = -i64; - } - WriteUint64((uint64_t)i64); - return true; - } + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char *p = buffer; - do { - *p++ = char(u64 % 10) + '0'; - u64 /= 10; - } while (u64 > 0); + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char *p = buffer; + do { + *p++ = char(u64 % 10) + '0'; + u64 /= 10; + } while (u64 > 0); - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } private: - OutputStream* os_; + OutputStream* os_; }; template<> bool Writer1::WriteUint(unsigned u) { - char buffer[10]; - char* p = buffer; - do { - *p++ = char(u % 10) + '0'; - u /= 10; - } while (u > 0); + char buffer[10]; + char* p = buffer; + do { + *p++ = char(u % 10) + '0'; + u /= 10; + } while (u > 0); - char* d = os_->Push(p - buffer); - do { - --p; - *d++ = *p; - } while (p != buffer); - return true; + char* d = os_->Push(p - buffer); + do { + --p; + *d++ = *p; + } while (p != buffer); + return true; } // Using digits LUT to reduce divsion/modulo template class Writer2 { public: - Writer2() : os_() {} - Writer2(OutputStream& os) : os_(&os) {} + Writer2() : os_() {} + Writer2(OutputStream& os) : os_(&os) {} - void Reset(OutputStream& os) { - os_ = &os; - } + void Reset(OutputStream& os) { + os_ = &os; + } - bool WriteInt(int i) { - if (i < 0) { - os_->Put('-'); - i = -i; - } - return WriteUint((unsigned)i); - } + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } - bool WriteUint(unsigned u) { - char buffer[10]; - char* p = buffer; - while (u >= 100) { - const unsigned i = (u % 100) << 1; - u /= 100; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } - if (u < 10) - *p++ = char(u) + '0'; - else { - const unsigned i = u << 1; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } + bool WriteUint(unsigned u) { + char buffer[10]; + char* p = buffer; + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u < 10) + *p++ = char(u) + '0'; + else { + const unsigned i = u << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } - bool WriteInt64(int64_t i64) { - if (i64 < 0) { - os_->Put('-'); - i64 = -i64; - } - WriteUint64((uint64_t)i64); - return true; - } + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char* p = buffer; - while (u64 >= 100) { - const unsigned i = static_cast(u64 % 100) << 1; - u64 /= 100; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } - if (u64 < 10) - *p++ = char(u64) + '0'; - else { - const unsigned i = static_cast(u64) << 1; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* p = buffer; + while (u64 >= 100) { + const unsigned i = static_cast(u64 % 100) << 1; + u64 /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u64 < 10) + *p++ = char(u64) + '0'; + else { + const unsigned i = static_cast(u64) << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } private: - OutputStream* os_; + OutputStream* os_; }; // First pass to count digits template class Writer3 { public: - Writer3() : os_() {} - Writer3(OutputStream& os) : os_(&os) {} + Writer3() : os_() {} + Writer3(OutputStream& os) : os_(&os) {} - void Reset(OutputStream& os) { - os_ = &os; - } + void Reset(OutputStream& os) { + os_ = &os; + } - bool WriteInt(int i) { - if (i < 0) { - os_->Put('-'); - i = -i; - } - return WriteUint((unsigned)i); - } + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } - bool WriteUint(unsigned u) { - char buffer[10]; - char *p = buffer; - do { - *p++ = char(u % 10) + '0'; - u /= 10; - } while (u > 0); + bool WriteUint(unsigned u) { + char buffer[10]; + char *p = buffer; + do { + *p++ = char(u % 10) + '0'; + u /= 10; + } while (u > 0); - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } - bool WriteInt64(int64_t i64) { - if (i64 < 0) { - os_->Put('-'); - i64 = -i64; - } - WriteUint64((uint64_t)i64); - return true; - } + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char *p = buffer; - do { - *p++ = char(u64 % 10) + '0'; - u64 /= 10; - } while (u64 > 0); + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char *p = buffer; + do { + *p++ = char(u64 % 10) + '0'; + u64 /= 10; + } while (u64 > 0); - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } private: - void WriteUintReverse(char* d, unsigned u) { - do { - *--d = char(u % 10) + '0'; - u /= 10; - } while (u > 0); - } + void WriteUintReverse(char* d, unsigned u) { + do { + *--d = char(u % 10) + '0'; + u /= 10; + } while (u > 0); + } - void WriteUint64Reverse(char* d, uint64_t u) { - do { - *--d = char(u % 10) + '0'; - u /= 10; - } while (u > 0); - } + void WriteUint64Reverse(char* d, uint64_t u) { + do { + *--d = char(u % 10) + '0'; + u /= 10; + } while (u > 0); + } - OutputStream* os_; + OutputStream* os_; }; template<> inline bool Writer3::WriteUint(unsigned u) { - unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Push(digit) + digit, u); + return true; } template<> inline bool Writer3::WriteUint(unsigned u) { - unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Push(digit) + digit, u); + return true; } template<> inline bool Writer3::WriteUint64(uint64_t u) { - unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Push(digit) + digit, u); + return true; } template<> inline bool Writer3::WriteUint64(uint64_t u) { - unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Push(digit) + digit, u); + return true; } // Using digits LUT to reduce divsion/modulo, two passes template class Writer4 { public: - Writer4() : os_() {} - Writer4(OutputStream& os) : os_(&os) {} + Writer4() : os_() {} + Writer4(OutputStream& os) : os_(&os) {} - void Reset(OutputStream& os) { - os_ = &os; - } + void Reset(OutputStream& os) { + os_ = &os; + } - bool WriteInt(int i) { - if (i < 0) { - os_->Put('-'); - i = -i; - } - return WriteUint((unsigned)i); - } + bool WriteInt(int i) { + if (i < 0) { + os_->Put('-'); + i = -i; + } + return WriteUint((unsigned)i); + } - bool WriteUint(unsigned u) { - char buffer[10]; - char* p = buffer; - while (u >= 100) { - const unsigned i = (u % 100) << 1; - u /= 100; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } - if (u < 10) - *p++ = char(u) + '0'; - else { - const unsigned i = u << 1; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } + bool WriteUint(unsigned u) { + char buffer[10]; + char* p = buffer; + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u < 10) + *p++ = char(u) + '0'; + else { + const unsigned i = u << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } - bool WriteInt64(int64_t i64) { - if (i64 < 0) { - os_->Put('-'); - i64 = -i64; - } - WriteUint64((uint64_t)i64); - return true; - } + bool WriteInt64(int64_t i64) { + if (i64 < 0) { + os_->Put('-'); + i64 = -i64; + } + WriteUint64((uint64_t)i64); + return true; + } - bool WriteUint64(uint64_t u64) { - char buffer[20]; - char* p = buffer; - while (u64 >= 100) { - const unsigned i = static_cast(u64 % 100) << 1; - u64 /= 100; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } - if (u64 < 10) - *p++ = char(u64) + '0'; - else { - const unsigned i = static_cast(u64) << 1; - *p++ = digits[i + 1]; - *p++ = digits[i]; - } + bool WriteUint64(uint64_t u64) { + char buffer[20]; + char* p = buffer; + while (u64 >= 100) { + const unsigned i = static_cast(u64 % 100) << 1; + u64 /= 100; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } + if (u64 < 10) + *p++ = char(u64) + '0'; + else { + const unsigned i = static_cast(u64) << 1; + *p++ = digits[i + 1]; + *p++ = digits[i]; + } - do { - --p; - os_->Put(*p); - } while (p != buffer); - return true; - } + do { + --p; + os_->Put(*p); + } while (p != buffer); + return true; + } private: - void WriteUintReverse(char* d, unsigned u) { - while (u >= 100) { - const unsigned i = (u % 100) << 1; - u /= 100; - *--d = digits[i + 1]; - *--d = digits[i]; - } - if (u < 10) { - *--d = char(u) + '0'; - } - else { - const unsigned i = u << 1; - *--d = digits[i + 1]; - *--d = digits[i]; - } - } + void WriteUintReverse(char* d, unsigned u) { + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *--d = digits[i + 1]; + *--d = digits[i]; + } + if (u < 10) { + *--d = char(u) + '0'; + } + else { + const unsigned i = u << 1; + *--d = digits[i + 1]; + *--d = digits[i]; + } + } - void WriteUint64Reverse(char* d, uint64_t u) { - while (u >= 100) { - const unsigned i = (u % 100) << 1; - u /= 100; - *--d = digits[i + 1]; - *--d = digits[i]; - } - if (u < 10) { - *--d = char(u) + '0'; - } - else { - const unsigned i = u << 1; - *--d = digits[i + 1]; - *--d = digits[i]; - } - } + void WriteUint64Reverse(char* d, uint64_t u) { + while (u >= 100) { + const unsigned i = (u % 100) << 1; + u /= 100; + *--d = digits[i + 1]; + *--d = digits[i]; + } + if (u < 10) { + *--d = char(u) + '0'; + } + else { + const unsigned i = u << 1; + *--d = digits[i + 1]; + *--d = digits[i]; + } + } - OutputStream* os_; + OutputStream* os_; }; template<> inline bool Writer4::WriteUint(unsigned u) { - unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Push(digit) + digit, u); + return true; } template<> inline bool Writer4::WriteUint(unsigned u) { - unsigned digit = CountDecimalDigit_fast(u); - WriteUintReverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit_fast(u); + WriteUintReverse(os_->Push(digit) + digit, u); + return true; } template<> inline bool Writer4::WriteUint64(uint64_t u) { - unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Push(digit) + digit, u); + return true; } template<> inline bool Writer4::WriteUint64(uint64_t u) { - unsigned digit = CountDecimalDigit64_fast(u); - WriteUint64Reverse(os_->Push(digit) + digit, u); - return true; + unsigned digit = CountDecimalDigit64_fast(u); + WriteUint64Reverse(os_->Push(digit) + digit, u); + return true; } template void itoa_Writer_StringBufferVerify() { - rapidjson::StringBuffer sb; - Writer writer(sb); - for (int j = 0; j < randvalCount; j++) { - char buffer[32]; - sprintf(buffer, "%d", randval[j]); - writer.WriteInt(randval[j]); - ASSERT_STREQ(buffer, sb.GetString()); - sb.Clear(); - } + rapidjson::StringBuffer sb; + Writer writer(sb); + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + sprintf(buffer, "%d", randval[j]); + writer.WriteInt(randval[j]); + ASSERT_STREQ(buffer, sb.GetString()); + sb.Clear(); + } } template void itoa_Writer_InsituStringStreamVerify() { - Writer writer; - for (int j = 0; j < randvalCount; j++) { - char buffer[32]; - sprintf(buffer, "%d", randval[j]); - char buffer2[32]; - rapidjson::InsituStringStream ss(buffer2); - writer.Reset(ss); - char* begin = ss.PutBegin(); - writer.WriteInt(randval[j]); - ss.Put('\0'); - ss.PutEnd(begin); - ASSERT_STREQ(buffer, buffer2); - } + Writer writer; + for (int j = 0; j < randvalCount; j++) { + char buffer[32]; + sprintf(buffer, "%d", randval[j]); + char buffer2[32]; + rapidjson::InsituStringStream ss(buffer2); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt(randval[j]); + ss.Put('\0'); + ss.PutEnd(begin); + ASSERT_STREQ(buffer, buffer2); + } } template void itoa_Writer_StringBuffer() { - size_t length = 0; + size_t length = 0; - rapidjson::StringBuffer sb; - Writer writer(sb); + rapidjson::StringBuffer sb; + Writer writer(sb); - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - writer.WriteInt(randval[j]); - length += sb.GetSize(); - sb.Clear(); - } - } - OUTPUT_LENGTH(length); + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + writer.WriteInt(randval[j]); + length += sb.GetSize(); + sb.Clear(); + } + } + OUTPUT_LENGTH(length); } template void itoa_Writer_InsituStringStream() { - size_t length = 0; + size_t length = 0; - char buffer[32]; - Writer writer; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - rapidjson::InsituStringStream ss(buffer); - writer.Reset(ss); - char* begin = ss.PutBegin(); - writer.WriteInt(randval[j]); - length += ss.PutEnd(begin); - } - } - OUTPUT_LENGTH(length); + char buffer[32]; + Writer writer; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + rapidjson::InsituStringStream ss(buffer); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt(randval[j]); + length += ss.PutEnd(begin); + } + } + OUTPUT_LENGTH(length); }; template void itoa64_Writer_StringBufferVerify() { - rapidjson::StringBuffer sb; - Writer writer(sb); - for (size_t j = 0; j < randvalCount; j++) { - char buffer[32]; - int64_t x = randval[j] * randval[j]; - sprintf(buffer, "%" PRIi64, x); - writer.WriteInt64(x); - ASSERT_STREQ(buffer, sb.GetString()); - sb.Clear(); - } + rapidjson::StringBuffer sb; + Writer writer(sb); + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + int64_t x = randval[j] * randval[j]; + sprintf(buffer, "%" PRIi64, x); + writer.WriteInt64(x); + ASSERT_STREQ(buffer, sb.GetString()); + sb.Clear(); + } } template void itoa64_Writer_InsituStringStreamVerify() { - Writer writer; - for (size_t j = 0; j < randvalCount; j++) { - char buffer[32]; - int64_t x = randval[j] * randval[j]; - sprintf(buffer, "%" PRIi64, x); - char buffer2[32]; - rapidjson::InsituStringStream ss(buffer2); - writer.Reset(ss); - char* begin = ss.PutBegin(); - writer.WriteInt64(x); - ss.Put('\0'); - ss.PutEnd(begin); - ASSERT_STREQ(buffer, buffer2); - } + Writer writer; + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + int64_t x = randval[j] * randval[j]; + sprintf(buffer, "%" PRIi64, x); + char buffer2[32]; + rapidjson::InsituStringStream ss(buffer2); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt64(x); + ss.Put('\0'); + ss.PutEnd(begin); + ASSERT_STREQ(buffer, buffer2); + } } template void itoa64_Writer_StringBuffer() { - size_t length = 0; + size_t length = 0; - rapidjson::StringBuffer sb; - Writer writer(sb); + rapidjson::StringBuffer sb; + Writer writer(sb); - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - writer.WriteInt64(randval[j] * randval[j]); - length += sb.GetSize(); - sb.Clear(); - } - } - OUTPUT_LENGTH(length); + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + writer.WriteInt64(randval[j] * randval[j]); + length += sb.GetSize(); + sb.Clear(); + } + } + OUTPUT_LENGTH(length); } template void itoa64_Writer_InsituStringStream() { - size_t length = 0; + size_t length = 0; - char buffer[32]; - Writer writer; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - rapidjson::InsituStringStream ss(buffer); - writer.Reset(ss); - char* begin = ss.PutBegin(); - writer.WriteInt64(randval[j] * randval[j]); - length += ss.PutEnd(begin); - } - } - OUTPUT_LENGTH(length); + char buffer[32]; + Writer writer; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + rapidjson::InsituStringStream ss(buffer); + writer.Reset(ss); + char* begin = ss.PutBegin(); + writer.WriteInt64(randval[j] * randval[j]); + length += ss.PutEnd(begin); + } + } + OUTPUT_LENGTH(length); }; // Full specialization for InsituStringStream to prevent memory copying @@ -907,34 +927,34 @@ namespace rapidjson { template<> bool rapidjson::Writer::WriteInt(int i) { - char *buffer = os_->Push(11); - const char* end = internal::i32toa(i, buffer); - os_->Pop(11 - (end - buffer)); - return true; + char *buffer = os_->Push(11); + const char* end = internal::i32toa(i, buffer); + os_->Pop(11 - (end - buffer)); + return true; } template<> bool Writer::WriteUint(unsigned u) { - char *buffer = os_->Push(10); - const char* end = internal::u32toa(u, buffer); - os_->Pop(10 - (end - buffer)); - return true; + char *buffer = os_->Push(10); + const char* end = internal::u32toa(u, buffer); + os_->Pop(10 - (end - buffer)); + return true; } template<> bool Writer::WriteInt64(int64_t i64) { - char *buffer = os_->Push(21); - const char* end = internal::i64toa(i64, buffer); - os_->Pop(21 - (end - buffer)); - return true; + char *buffer = os_->Push(21); + const char* end = internal::i64toa(i64, buffer); + os_->Pop(21 - (end - buffer)); + return true; } template<> bool Writer::WriteUint64(uint64_t u) { - char *buffer = os_->Push(20); - const char* end = internal::u64toa(u, buffer); - os_->Pop(20 - (end - buffer)); - return true; + char *buffer = os_->Push(20); + const char* end = internal::u64toa(u, buffer); + os_->Pop(20 - (end - buffer)); + return true; } } // namespace rapidjson @@ -982,106 +1002,106 @@ TEST_F(Misc, itoa64_Writer3_InsituStringStream) { itoa64_Writer_InsituStringStre TEST_F(Misc, itoa64_Writer4_InsituStringStream) { itoa64_Writer_InsituStringStream >(); } TEST_F(Misc, itoa_sprintf) { - size_t length = 0; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - char buffer[32]; - length += sprintf(buffer, "%d", randval[j]); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + length += sprintf(buffer, "%d", randval[j]); + } + } + OUTPUT_LENGTH(length); } TEST_F(Misc, itoa64_sprintf) { - size_t length = 0; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - char buffer[32]; - int64_t x = randval[j] * randval[j]; - length += sprintf(buffer, "%" PRIi64, x); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + int64_t x = randval[j] * randval[j]; + length += sprintf(buffer, "%" PRIi64, x); + } + } + OUTPUT_LENGTH(length); } #ifdef _MSC_VER TEST_F(Misc, itoa_VC) { - size_t length = 0; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - char buffer[32]; - _itoa(randval[j], buffer, 10); - length += strlen(buffer); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + _itoa(randval[j], buffer, 10); + length += strlen(buffer); + } + } + OUTPUT_LENGTH(length); } TEST_F(Misc, itoa64_VC) { - size_t length = 0; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - char buffer[32]; - _i64toa(randval[j] * randval[j], buffer, 10); - length += strlen(buffer); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char buffer[32]; + _i64toa(randval[j] * randval[j], buffer, 10); + length += strlen(buffer); + } + } + OUTPUT_LENGTH(length); } #endif TEST_F(Misc, itoa_strtk) { - size_t length = 0; - std::string s; - s.reserve(32); - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - s = strtk::type_to_string(randval[j]); - length += s.size(); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + std::string s; + s.reserve(32); + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + s = strtk::type_to_string(randval[j]); + length += s.size(); + } + } + OUTPUT_LENGTH(length); } TEST_F(Misc, itoa64_strtk) { - size_t length = 0; - std::string s; - s.reserve(32); - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - int64_t x = randval[j] * randval[j]; - s = strtk::type_to_string(x); - length += s.size(); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + std::string s; + s.reserve(32); + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + int64_t x = randval[j] * randval[j]; + s = strtk::type_to_string(x); + length += s.size(); + } + } + OUTPUT_LENGTH(length); } TEST_F(Misc, itoa_cppformat) { - size_t length = 0; - char buffer[32]; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - char* p = buffer; - fmt::FormatDec(p, randval[j]); - length += (p - buffer); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + char buffer[32]; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char* p = buffer; + fmt::FormatDec(p, randval[j]); + length += (p - buffer); + } + } + OUTPUT_LENGTH(length); } TEST_F(Misc, itoa64_cppformat) { - size_t length = 0; - char buffer[32]; - for (size_t i = 0; i < kItoaTrialCount; i++) { - for (size_t j = 0; j < randvalCount; j++) { - char* p = buffer; - int64_t x = randval[j] * randval[j]; - fmt::FormatDec(p, x); - length += (p - buffer); - } - } - OUTPUT_LENGTH(length); + size_t length = 0; + char buffer[32]; + for (size_t i = 0; i < kItoaTrialCount; i++) { + for (size_t j = 0; j < randvalCount; j++) { + char* p = buffer; + int64_t x = randval[j] * randval[j]; + fmt::FormatDec(p, x); + length += (p - buffer); + } + } + OUTPUT_LENGTH(length); } #endif // TEST_MISC diff --git a/test/perftest/perftest.cpp b/test/perftest/perftest.cpp index fac4c2f..4366e1c 100644 --- a/test/perftest/perftest.cpp +++ b/test/perftest/perftest.cpp @@ -1,10 +1,30 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "perftest.h" int main(int argc, char **argv) { #if _MSC_VER - _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); - //void *testWhetherMemoryLeakDetectionWorks = malloc(1); + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); + //void *testWhetherMemoryLeakDetectionWorks = malloc(1); #endif - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/test/perftest/perftest.h b/test/perftest/perftest.h index be36920..81b4011 100644 --- a/test/perftest/perftest.h +++ b/test/perftest/perftest.h @@ -1,12 +1,32 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef PERFTEST_H_ #define PERFTEST_H_ -#define TEST_RAPIDJSON 1 -#define TEST_JSONCPP 0 -#define TEST_YAJL 0 +#define TEST_RAPIDJSON 1 +#define TEST_JSONCPP 0 +#define TEST_YAJL 0 #define TEST_ULTRAJSON 0 #define TEST_PLATFORM 0 -#define TEST_MISC 0 +#define TEST_MISC 0 #define TEST_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) @@ -55,57 +75,57 @@ //! Base class for all performance tests class PerfTest : public ::testing::Test { public: - PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {} + PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {} - virtual void SetUp() { - FILE *fp = fopen(filename_ = "data/sample.json", "rb"); - if (!fp) - fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); - ASSERT_TRUE(fp != 0); + virtual void SetUp() { + FILE *fp = fopen(filename_ = "data/sample.json", "rb"); + if (!fp) + fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); + ASSERT_TRUE(fp != 0); - fseek(fp, 0, SEEK_END); - length_ = (size_t)ftell(fp); - fseek(fp, 0, SEEK_SET); - json_ = (char*)malloc(length_ + 1); - ASSERT_EQ(length_, fread(json_, 1, length_, fp)); - json_[length_] = '\0'; - fclose(fp); + fseek(fp, 0, SEEK_END); + length_ = (size_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + json_ = (char*)malloc(length_ + 1); + ASSERT_EQ(length_, fread(json_, 1, length_, fp)); + json_[length_] = '\0'; + fclose(fp); - // whitespace test - whitespace_length_ = 1024 * 1024; - whitespace_ = (char *)malloc(whitespace_length_ + 4); - char *p = whitespace_; - for (size_t i = 0; i < whitespace_length_; i += 4) { - *p++ = ' '; - *p++ = '\n'; - *p++ = '\r'; - *p++ = '\t'; - } - *p++ = '['; - *p++ = '0'; - *p++ = ']'; - *p++ = '\0'; - } + // whitespace test + whitespace_length_ = 1024 * 1024; + whitespace_ = (char *)malloc(whitespace_length_ + 4); + char *p = whitespace_; + for (size_t i = 0; i < whitespace_length_; i += 4) { + *p++ = ' '; + *p++ = '\n'; + *p++ = '\r'; + *p++ = '\t'; + } + *p++ = '['; + *p++ = '0'; + *p++ = ']'; + *p++ = '\0'; + } - virtual void TearDown() { - free(json_); - free(whitespace_); - json_ = 0; - whitespace_ = 0; - } + virtual void TearDown() { + free(json_); + free(whitespace_); + json_ = 0; + whitespace_ = 0; + } private: - PerfTest(const PerfTest&); - PerfTest& operator=(const PerfTest&); + PerfTest(const PerfTest&); + PerfTest& operator=(const PerfTest&); protected: - const char* filename_; - char *json_; - size_t length_; - char *whitespace_; - size_t whitespace_length_; + const char* filename_; + char *json_; + size_t length_; + char *whitespace_; + size_t whitespace_length_; - static const size_t kTrialCount = 1000; + static const size_t kTrialCount = 1000; }; #endif // __cplusplus diff --git a/test/perftest/platformtest.cpp b/test/perftest/platformtest.cpp index badb0c9..30b690c 100644 --- a/test/perftest/platformtest.cpp +++ b/test/perftest/platformtest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "perftest.h" // This file is for giving the performance characteristics of the platform (compiler/OS/CPU). @@ -22,130 +42,130 @@ class Platform : public PerfTest { public: - virtual void SetUp() { - PerfTest::SetUp(); + virtual void SetUp() { + PerfTest::SetUp(); - // temp buffer for testing - temp_ = (char *)malloc(length_ + 1); - memcpy(temp_, json_, length_); - checkSum_ = CheckSum(); - } + // temp buffer for testing + temp_ = (char *)malloc(length_ + 1); + memcpy(temp_, json_, length_); + checkSum_ = CheckSum(); + } - char CheckSum() { - char c = 0; - for (size_t i = 0; i < length_; ++i) - c += temp_[i]; - return c; - } + char CheckSum() { + char c = 0; + for (size_t i = 0; i < length_; ++i) + c += temp_[i]; + return c; + } - virtual void TearDown() { - PerfTest::TearDown(); - free(temp_); - } + virtual void TearDown() { + PerfTest::TearDown(); + free(temp_); + } protected: - char *temp_; - char checkSum_; + char *temp_; + char checkSum_; }; TEST_F(Platform, CheckSum) { - for (int i = 0; i < kTrialCount; i++) - EXPECT_EQ(checkSum_, CheckSum()); + for (int i = 0; i < kTrialCount; i++) + EXPECT_EQ(checkSum_, CheckSum()); } TEST_F(Platform, strlen) { - for (int i = 0; i < kTrialCount; i++) { - size_t l = strlen(json_); - EXPECT_EQ(length_, l); - } + for (int i = 0; i < kTrialCount; i++) { + size_t l = strlen(json_); + EXPECT_EQ(length_, l); + } } TEST_F(Platform, memcmp) { - for (int i = 0; i < kTrialCount; i++) { - EXPECT_EQ(0, memcmp(temp_, json_, length_)); - } + for (int i = 0; i < kTrialCount; i++) { + EXPECT_EQ(0, memcmp(temp_, json_, length_)); + } } TEST_F(Platform, pow) { - double sum = 0; - for (int i = 0; i < kTrialCount * kTrialCount; i++) - sum += pow(10.0, i & 255); - EXPECT_GT(sum, 0.0); + double sum = 0; + for (int i = 0; i < kTrialCount * kTrialCount; i++) + sum += pow(10.0, i & 255); + EXPECT_GT(sum, 0.0); } TEST_F(Platform, Whitespace_strlen) { - for (int i = 0; i < kTrialCount; i++) { - size_t l = strlen(whitespace_); - EXPECT_GT(l, whitespace_length_); - } + for (int i = 0; i < kTrialCount; i++) { + size_t l = strlen(whitespace_); + EXPECT_GT(l, whitespace_length_); + } } TEST_F(Platform, Whitespace_strspn) { - for (int i = 0; i < kTrialCount; i++) { - size_t l = strspn(whitespace_, " \n\r\t"); - EXPECT_EQ(whitespace_length_, l); - } + for (int i = 0; i < kTrialCount; i++) { + size_t l = strspn(whitespace_, " \n\r\t"); + EXPECT_EQ(whitespace_length_, l); + } } TEST_F(Platform, fread) { - for (int i = 0; i < kTrialCount; i++) { - FILE *fp = fopen(filename_, "rb"); - ASSERT_EQ(length_, fread(temp_, 1, length_, fp)); - EXPECT_EQ(checkSum_, CheckSum()); - fclose(fp); - } + for (int i = 0; i < kTrialCount; i++) { + FILE *fp = fopen(filename_, "rb"); + ASSERT_EQ(length_, fread(temp_, 1, length_, fp)); + EXPECT_EQ(checkSum_, CheckSum()); + fclose(fp); + } } #ifdef _MSC_VER TEST_F(Platform, read) { - for (int i = 0; i < kTrialCount; i++) { - int fd = _open(filename_, _O_BINARY | _O_RDONLY); - ASSERT_NE(-1, fd); - ASSERT_EQ(length_, _read(fd, temp_, length_)); - EXPECT_EQ(checkSum_, CheckSum()); - _close(fd); - } + for (int i = 0; i < kTrialCount; i++) { + int fd = _open(filename_, _O_BINARY | _O_RDONLY); + ASSERT_NE(-1, fd); + ASSERT_EQ(length_, _read(fd, temp_, length_)); + EXPECT_EQ(checkSum_, CheckSum()); + _close(fd); + } } #else TEST_F(Platform, read) { - for (int i = 0; i < kTrialCount; i++) { - int fd = open(filename_, O_RDONLY); - ASSERT_NE(-1, fd); - ASSERT_EQ(length_, read(fd, temp_, length_)); - EXPECT_EQ(checkSum_, CheckSum()); - close(fd); - } + for (int i = 0; i < kTrialCount; i++) { + int fd = open(filename_, O_RDONLY); + ASSERT_NE(-1, fd); + ASSERT_EQ(length_, read(fd, temp_, length_)); + EXPECT_EQ(checkSum_, CheckSum()); + close(fd); + } } #endif #ifdef _WIN32 TEST_F(Platform, MapViewOfFile) { - for (int i = 0; i < kTrialCount; i++) { - HANDLE file = CreateFile(filename_, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - ASSERT_NE(INVALID_HANDLE_VALUE, file); - HANDLE mapObject = CreateFileMapping(file, NULL, PAGE_READONLY, 0, length_, NULL); - ASSERT_NE(INVALID_HANDLE_VALUE, mapObject); - void *p = MapViewOfFile(mapObject, FILE_MAP_READ, 0, 0, length_); - ASSERT_TRUE(p != NULL); - EXPECT_EQ(checkSum_, CheckSum()); - ASSERT_TRUE(UnmapViewOfFile(p) == TRUE); - ASSERT_TRUE(CloseHandle(mapObject) == TRUE); - ASSERT_TRUE(CloseHandle(file) == TRUE); - } + for (int i = 0; i < kTrialCount; i++) { + HANDLE file = CreateFile(filename_, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + ASSERT_NE(INVALID_HANDLE_VALUE, file); + HANDLE mapObject = CreateFileMapping(file, NULL, PAGE_READONLY, 0, length_, NULL); + ASSERT_NE(INVALID_HANDLE_VALUE, mapObject); + void *p = MapViewOfFile(mapObject, FILE_MAP_READ, 0, 0, length_); + ASSERT_TRUE(p != NULL); + EXPECT_EQ(checkSum_, CheckSum()); + ASSERT_TRUE(UnmapViewOfFile(p) == TRUE); + ASSERT_TRUE(CloseHandle(mapObject) == TRUE); + ASSERT_TRUE(CloseHandle(file) == TRUE); + } } #endif #ifdef _POSIX_MAPPED_FILES TEST_F(Platform, mmap) { - for (int i = 0; i < kTrialCount; i++) { - int fd = open(filename_, O_RDONLY); - ASSERT_NE(-1, fd); - void *p = mmap(NULL, length_, PROT_READ, MAP_PRIVATE, fd, 0); - ASSERT_TRUE(p != NULL); - EXPECT_EQ(checkSum_, CheckSum()); - munmap(p, length_); - close(fd); - } + for (int i = 0; i < kTrialCount; i++) { + int fd = open(filename_, O_RDONLY); + ASSERT_NE(-1, fd); + void *p = mmap(NULL, length_, PROT_READ, MAP_PRIVATE, fd, 0); + ASSERT_TRUE(p != NULL); + EXPECT_EQ(checkSum_, CheckSum()); + munmap(p, length_); + close(fd); + } } #endif diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 95a407d..6a45113 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "perftest.h" #if TEST_RAPIDJSON @@ -21,162 +41,162 @@ using namespace rapidjson; class RapidJson : public PerfTest { public: - RapidJson() : temp_(), doc_() {} + RapidJson() : temp_(), doc_() {} - virtual void SetUp() { - PerfTest::SetUp(); + virtual void SetUp() { + PerfTest::SetUp(); - // temp buffer for insitu parsing. - temp_ = (char *)malloc(length_ + 1); + // temp buffer for insitu parsing. + temp_ = (char *)malloc(length_ + 1); - // Parse as a document - EXPECT_FALSE(doc_.Parse(json_).IsNull()); - } + // Parse as a document + EXPECT_FALSE(doc_.Parse(json_).IsNull()); + } - virtual void TearDown() { - PerfTest::TearDown(); - free(temp_); - } + virtual void TearDown() { + PerfTest::TearDown(); + free(temp_); + } private: - RapidJson(const RapidJson&); - RapidJson& operator=(const RapidJson&); + RapidJson(const RapidJson&); + RapidJson& operator=(const RapidJson&); protected: - char *temp_; - Document doc_; + char *temp_; + Document doc_; }; TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler)) { - for (size_t i = 0; i < kTrialCount; i++) { - memcpy(temp_, json_, length_ + 1); - InsituStringStream s(temp_); - BaseReaderHandler<> h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - } + for (size_t i = 0; i < kTrialCount; i++) { + memcpy(temp_, json_, length_ + 1); + InsituStringStream s(temp_); + BaseReaderHandler<> h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } } TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler_ValidateEncoding)) { - for (size_t i = 0; i < kTrialCount; i++) { - memcpy(temp_, json_, length_ + 1); - InsituStringStream s(temp_); - BaseReaderHandler<> h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - } + for (size_t i = 0; i < kTrialCount; i++) { + memcpy(temp_, json_, length_ + 1); + InsituStringStream s(temp_); + BaseReaderHandler<> h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } } TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) { - for (size_t i = 0; i < kTrialCount; i++) { - StringStream s(json_); - BaseReaderHandler<> h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - } + for (size_t i = 0; i < kTrialCount; i++) { + StringStream s(json_); + BaseReaderHandler<> h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } } TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterative_DummyHandler)) { - for (size_t i = 0; i < kTrialCount; i++) { - StringStream s(json_); - BaseReaderHandler<> h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - } + for (size_t i = 0; i < kTrialCount; i++) { + StringStream s(json_); + BaseReaderHandler<> h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } } TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseIterativeInsitu_DummyHandler)) { - for (size_t i = 0; i < kTrialCount; i++) { - memcpy(temp_, json_, length_ + 1); - InsituStringStream s(temp_); - BaseReaderHandler<> h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - } + for (size_t i = 0; i < kTrialCount; i++) { + memcpy(temp_, json_, length_ + 1); + InsituStringStream s(temp_); + BaseReaderHandler<> h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } } TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_ValidateEncoding)) { - for (size_t i = 0; i < kTrialCount; i++) { - StringStream s(json_); - BaseReaderHandler<> h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - } + for (size_t i = 0; i < kTrialCount; i++) { + StringStream s(json_); + BaseReaderHandler<> h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + } } TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseInsitu_MemoryPoolAllocator)) { - for (size_t i = 0; i < kTrialCount; i++) { - memcpy(temp_, json_, length_ + 1); - Document doc; - doc.ParseInsitu(temp_); - ASSERT_TRUE(doc.IsObject()); - } + for (size_t i = 0; i < kTrialCount; i++) { + memcpy(temp_, json_, length_ + 1); + Document doc; + doc.ParseInsitu(temp_); + ASSERT_TRUE(doc.IsObject()); + } } TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseIterativeInsitu_MemoryPoolAllocator)) { - for (size_t i = 0; i < kTrialCount; i++) { - memcpy(temp_, json_, length_ + 1); - Document doc; - doc.ParseInsitu(temp_); - ASSERT_TRUE(doc.IsObject()); - } + for (size_t i = 0; i < kTrialCount; i++) { + memcpy(temp_, json_, length_ + 1); + Document doc; + doc.ParseInsitu(temp_); + ASSERT_TRUE(doc.IsObject()); + } } TEST_F(RapidJson, SIMD_SUFFIX(DocumentParse_MemoryPoolAllocator)) { - for (size_t i = 0; i < kTrialCount; i++) { - Document doc; - doc.Parse(json_); - ASSERT_TRUE(doc.IsObject()); - } + for (size_t i = 0; i < kTrialCount; i++) { + Document doc; + doc.Parse(json_); + ASSERT_TRUE(doc.IsObject()); + } } TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseIterative_MemoryPoolAllocator)) { - for (size_t i = 0; i < kTrialCount; i++) { - Document doc; - doc.Parse(json_); - ASSERT_TRUE(doc.IsObject()); - } + for (size_t i = 0; i < kTrialCount; i++) { + Document doc; + doc.Parse(json_); + ASSERT_TRUE(doc.IsObject()); + } } TEST_F(RapidJson, SIMD_SUFFIX(DocumentParse_CrtAllocator)) { - for (size_t i = 0; i < kTrialCount; i++) { - memcpy(temp_, json_, length_ + 1); - GenericDocument, CrtAllocator> doc; - doc.Parse(temp_); - ASSERT_TRUE(doc.IsObject()); - } + for (size_t i = 0; i < kTrialCount; i++) { + memcpy(temp_, json_, length_ + 1); + GenericDocument, CrtAllocator> doc; + doc.Parse(temp_); + ASSERT_TRUE(doc.IsObject()); + } } template size_t Traverse(const T& value) { - size_t count = 1; - switch(value.GetType()) { - case kObjectType: - for (typename T::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) { - count++; // name - count += Traverse(itr->value); - } - break; + size_t count = 1; + switch(value.GetType()) { + case kObjectType: + for (typename T::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) { + count++; // name + count += Traverse(itr->value); + } + break; - case kArrayType: - for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr) - count += Traverse(*itr); - break; + case kArrayType: + for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr) + count += Traverse(*itr); + break; - default: - // Do nothing. - break; - } - return count; + default: + // Do nothing. + break; + } + return count; } TEST_F(RapidJson, DocumentTraverse) { - for (size_t i = 0; i < kTrialCount; i++) { - size_t count = Traverse(doc_); - EXPECT_EQ(4339u, count); - //if (i == 0) - // std::cout << count << std::endl; - } + for (size_t i = 0; i < kTrialCount; i++) { + size_t count = Traverse(doc_); + EXPECT_EQ(4339u, count); + //if (i == 0) + // std::cout << count << std::endl; + } } #ifdef __GNUC__ @@ -185,12 +205,12 @@ RAPIDJSON_DIAG_OFF(effc++) #endif struct ValueCounter : public BaseReaderHandler<> { - ValueCounter() : count_(1) {} // root + ValueCounter() : count_(1) {} // root - bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; } - bool EndArray(SizeType elementCount) { count_ += elementCount; return true; } + bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; } + bool EndArray(SizeType elementCount) { count_ += elementCount; return true; } - SizeType count_; + SizeType count_; }; #ifdef __GNUC__ @@ -198,113 +218,113 @@ RAPIDJSON_DIAG_POP #endif TEST_F(RapidJson, DocumentAccept) { - for (size_t i = 0; i < kTrialCount; i++) { - ValueCounter counter; - doc_.Accept(counter); - EXPECT_EQ(4339u, counter.count_); - } + for (size_t i = 0; i < kTrialCount; i++) { + ValueCounter counter; + doc_.Accept(counter); + EXPECT_EQ(4339u, counter.count_); + } } struct NullStream { - NullStream() /*: length_(0)*/ {} - void Put(char) { /*++length_;*/ } - void Flush() {} - //size_t length_; + NullStream() /*: length_(0)*/ {} + void Put(char) { /*++length_;*/ } + void Flush() {} + //size_t length_; }; TEST_F(RapidJson, Writer_NullStream) { - for (size_t i = 0; i < kTrialCount; i++) { - NullStream s; - Writer writer(s); - doc_.Accept(writer); - //if (i == 0) - // std::cout << s.length_ << std::endl; - } + for (size_t i = 0; i < kTrialCount; i++) { + NullStream s; + Writer writer(s); + doc_.Accept(writer); + //if (i == 0) + // std::cout << s.length_ << std::endl; + } } TEST_F(RapidJson, Writer_StringBuffer) { - for (size_t i = 0; i < kTrialCount; i++) { - StringBuffer s(0, 1024 * 1024); - Writer writer(s); - doc_.Accept(writer); - const char* str = s.GetString(); - (void)str; - //if (i == 0) - // std::cout << strlen(str) << std::endl; - } + for (size_t i = 0; i < kTrialCount; i++) { + StringBuffer s(0, 1024 * 1024); + Writer writer(s); + doc_.Accept(writer); + const char* str = s.GetString(); + (void)str; + //if (i == 0) + // std::cout << strlen(str) << std::endl; + } } TEST_F(RapidJson, PrettyWriter_StringBuffer) { - for (size_t i = 0; i < kTrialCount; i++) { - StringBuffer s(0, 2048 * 1024); - PrettyWriter writer(s); - writer.SetIndent(' ', 1); - doc_.Accept(writer); - const char* str = s.GetString(); - (void)str; - //if (i == 0) - // std::cout << strlen(str) << std::endl; - } + for (size_t i = 0; i < kTrialCount; i++) { + StringBuffer s(0, 2048 * 1024); + PrettyWriter writer(s); + writer.SetIndent(' ', 1); + doc_.Accept(writer); + const char* str = s.GetString(); + (void)str; + //if (i == 0) + // std::cout << strlen(str) << std::endl; + } } TEST_F(RapidJson, internal_Pow10) { - double sum = 0; - for (size_t i = 0; i < kTrialCount * kTrialCount; i++) - sum += internal::Pow10(int(i & 255)); - EXPECT_GT(sum, 0.0); + double sum = 0; + for (size_t i = 0; i < kTrialCount * kTrialCount; i++) + sum += internal::Pow10(int(i & 255)); + EXPECT_GT(sum, 0.0); } TEST_F(RapidJson, SIMD_SUFFIX(Whitespace)) { - for (size_t i = 0; i < kTrialCount; i++) { - Document doc; - ASSERT_TRUE(doc.Parse(whitespace_).IsArray()); - } + for (size_t i = 0; i < kTrialCount; i++) { + Document doc; + ASSERT_TRUE(doc.Parse(whitespace_).IsArray()); + } } TEST_F(RapidJson, UTF8_Validate) { - NullStream os; + NullStream os; - for (size_t i = 0; i < kTrialCount; i++) { - StringStream is(json_); - bool result = true; - while (is.Peek() != '\0') - result &= UTF8<>::Validate(is, os); - EXPECT_TRUE(result); - } + for (size_t i = 0; i < kTrialCount; i++) { + StringStream is(json_); + bool result = true; + while (is.Peek() != '\0') + result &= UTF8<>::Validate(is, os); + EXPECT_TRUE(result); + } } // Depreciated. //TEST_F(RapidJson, FileStream_Read) { -// for (size_t i = 0; i < kTrialCount; i++) { -// FILE *fp = fopen(filename_, "rb"); -// FileStream s(fp); -// while (s.Take() != '\0') -// ; -// fclose(fp); -// } +// for (size_t i = 0; i < kTrialCount; i++) { +// FILE *fp = fopen(filename_, "rb"); +// FileStream s(fp); +// while (s.Take() != '\0') +// ; +// fclose(fp); +// } //} TEST_F(RapidJson, FileReadStream) { - for (size_t i = 0; i < kTrialCount; i++) { - FILE *fp = fopen(filename_, "rb"); - char buffer[65536]; - FileReadStream s(fp, buffer, sizeof(buffer)); - while (s.Take() != '\0') - ; - fclose(fp); - } + for (size_t i = 0; i < kTrialCount; i++) { + FILE *fp = fopen(filename_, "rb"); + char buffer[65536]; + FileReadStream s(fp, buffer, sizeof(buffer)); + while (s.Take() != '\0') + ; + fclose(fp); + } } TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) { - for (size_t i = 0; i < kTrialCount; i++) { - FILE *fp = fopen(filename_, "rb"); - char buffer[65536]; - FileReadStream s(fp, buffer, sizeof(buffer)); - BaseReaderHandler<> h; - Reader reader; - reader.Parse(s, h); - fclose(fp); - } + for (size_t i = 0; i < kTrialCount; i++) { + FILE *fp = fopen(filename_, "rb"); + char buffer[65536]; + FileReadStream s(fp, buffer, sizeof(buffer)); + BaseReaderHandler<> h; + Reader reader; + reader.Parse(s, h); + fclose(fp); + } } #endif // TEST_RAPIDJSON diff --git a/test/perftest/ultrajsontest.cpp b/test/perftest/ultrajsontest.cpp index 8328c63..028fcdc 100644 --- a/test/perftest/ultrajsontest.cpp +++ b/test/perftest/ultrajsontest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "perftest.h" #if TEST_ULTRAJSON @@ -13,52 +33,52 @@ static char dummy = 0; static void Object_objectAddKey(JSOBJ obj, JSOBJ name, JSOBJ value) {} static void Object_arrayAddItem(JSOBJ obj, JSOBJ value) {} -static JSOBJ Object_newString(wchar_t *start, wchar_t *end) { return &dummy; } -static JSOBJ Object_newTrue(void) { return &dummy; } -static JSOBJ Object_newFalse(void) { return &dummy; } -static JSOBJ Object_newNull(void) { return &dummy; } -static JSOBJ Object_newObject(void) { return &dummy; } -static JSOBJ Object_newArray(void) { return &dummy; } -static JSOBJ Object_newInteger(JSINT32 value) { return &dummy; } -static JSOBJ Object_newLong(JSINT64 value) { return &dummy; } -static JSOBJ Object_newDouble(double value) { return &dummy; } +static JSOBJ Object_newString(wchar_t *start, wchar_t *end) { return &dummy; } +static JSOBJ Object_newTrue(void) { return &dummy; } +static JSOBJ Object_newFalse(void) { return &dummy; } +static JSOBJ Object_newNull(void) { return &dummy; } +static JSOBJ Object_newObject(void) { return &dummy; } +static JSOBJ Object_newArray(void) { return &dummy; } +static JSOBJ Object_newInteger(JSINT32 value) { return &dummy; } +static JSOBJ Object_newLong(JSINT64 value) { return &dummy; } +static JSOBJ Object_newDouble(double value) { return &dummy; } static void Object_releaseObject(JSOBJ obj) {} static JSONObjectDecoder decoder = { - Object_newString, - Object_objectAddKey, - Object_arrayAddItem, - Object_newTrue, - Object_newFalse, - Object_newNull, - Object_newObject, - Object_newArray, - Object_newInteger, - Object_newLong, - Object_newDouble, - Object_releaseObject, - malloc, - free, - realloc + Object_newString, + Object_objectAddKey, + Object_arrayAddItem, + Object_newTrue, + Object_newFalse, + Object_newNull, + Object_newObject, + Object_newArray, + Object_newInteger, + Object_newLong, + Object_newDouble, + Object_releaseObject, + malloc, + free, + realloc }; TEST_F(UltraJson, Decode) { - for (int i = 0; i < kTrialCount; i++) { - decoder.errorStr = NULL; - decoder.errorOffset = NULL; - void *ret = JSON_DecodeObject(&decoder, json_, length_); - ASSERT_TRUE(ret != 0); - } + for (int i = 0; i < kTrialCount; i++) { + decoder.errorStr = NULL; + decoder.errorOffset = NULL; + void *ret = JSON_DecodeObject(&decoder, json_, length_); + ASSERT_TRUE(ret != 0); + } } TEST_F(UltraJson, Whitespace) { - for (int i = 0; i < kTrialCount; i++) { - decoder.errorStr = NULL; - decoder.errorOffset = NULL; - void *ret = JSON_DecodeObject(&decoder, whitespace_, whitespace_length_); - ASSERT_TRUE(ret != 0); - } + for (int i = 0; i < kTrialCount; i++) { + decoder.errorStr = NULL; + decoder.errorOffset = NULL; + void *ret = JSON_DecodeObject(&decoder, whitespace_, whitespace_length_); + ASSERT_TRUE(ret != 0); + } } #endif // TEST_ULTRAJSON diff --git a/test/perftest/yajltest.cpp b/test/perftest/yajltest.cpp index 8717316..32d851a 100644 --- a/test/perftest/yajltest.cpp +++ b/test/perftest/yajltest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "perftest.h" #if TEST_YAJL @@ -10,19 +30,19 @@ extern "C" { class Yajl : public PerfTest { public: - virtual void SetUp() { - PerfTest::SetUp(); - root_ = yajl_tree_parse(json_, NULL, 0); - ASSERT_TRUE(root_ != NULL); - } + virtual void SetUp() { + PerfTest::SetUp(); + root_ = yajl_tree_parse(json_, NULL, 0); + ASSERT_TRUE(root_ != NULL); + } - virtual void TearDown() { - PerfTest::TearDown(); - yajl_tree_free(root_); - } + virtual void TearDown() { + PerfTest::TearDown(); + yajl_tree_free(root_); + } protected: - yajl_val root_; + yajl_val root_; }; static int null_null(void *) { return 1; } @@ -37,152 +57,152 @@ static int null_start_array(void*) { return 1; } static int null_end_array(void *) { return 1; } static yajl_callbacks nullcallbacks = { - null_null, - null_boolean, - null_integer, - null_double, - NULL, // yajl_number(). Here we want to test full-parsing performance. - null_string, - null_start_map, - null_map_key, - null_end_map, - null_start_array, - null_end_array + null_null, + null_boolean, + null_integer, + null_double, + NULL, // yajl_number(). Here we want to test full-parsing performance. + null_string, + null_start_map, + null_map_key, + null_end_map, + null_start_array, + null_end_array }; TEST_F(Yajl, yajl_parse_nullcallbacks) { - for (int i = 0; i < kTrialCount; i++) { - yajl_handle hand = yajl_alloc(&nullcallbacks, NULL, NULL); - yajl_status stat = yajl_parse(hand, (unsigned char*)json_, length_); - //ASSERT_EQ(yajl_status_ok, stat); - if (stat != yajl_status_ok) { - unsigned char * str = yajl_get_error(hand, 1, (unsigned char*)json_, length_); - fprintf(stderr, "%s", (const char *) str); - } - stat = yajl_complete_parse(hand); - ASSERT_EQ(yajl_status_ok, stat); - yajl_free(hand); - } + for (int i = 0; i < kTrialCount; i++) { + yajl_handle hand = yajl_alloc(&nullcallbacks, NULL, NULL); + yajl_status stat = yajl_parse(hand, (unsigned char*)json_, length_); + //ASSERT_EQ(yajl_status_ok, stat); + if (stat != yajl_status_ok) { + unsigned char * str = yajl_get_error(hand, 1, (unsigned char*)json_, length_); + fprintf(stderr, "%s", (const char *) str); + } + stat = yajl_complete_parse(hand); + ASSERT_EQ(yajl_status_ok, stat); + yajl_free(hand); + } } TEST_F(Yajl, yajl_tree_parse) { - for (int i = 0; i < kTrialCount; i++) { - yajl_val root = yajl_tree_parse(json_, NULL, 0); - ASSERT_TRUE(root != NULL); - yajl_tree_free(root); - } + for (int i = 0; i < kTrialCount; i++) { + yajl_val root = yajl_tree_parse(json_, NULL, 0); + ASSERT_TRUE(root != NULL); + yajl_tree_free(root); + } } yajl_gen_status GenVal(yajl_gen g, yajl_val v) { - yajl_gen_status status; - switch (v->type) { - case yajl_t_string: return yajl_gen_string(g, (unsigned char*)v->u.string, strlen(v->u.string)); + yajl_gen_status status; + switch (v->type) { + case yajl_t_string: return yajl_gen_string(g, (unsigned char*)v->u.string, strlen(v->u.string)); - case yajl_t_number: - { - char buffer[100]; - char *num = buffer; - size_t len; - //if (YAJL_IS_INTEGER(v)) // buggy - if (v->u.number.flags & YAJL_NUMBER_INT_VALID) + case yajl_t_number: + { + char buffer[100]; + char *num = buffer; + size_t len; + //if (YAJL_IS_INTEGER(v)) // buggy + if (v->u.number.flags & YAJL_NUMBER_INT_VALID) #if _MSC_VER - len = sprintf(num, "%I64d", YAJL_GET_INTEGER(v)); + len = sprintf(num, "%I64d", YAJL_GET_INTEGER(v)); #else - len = sprintf(num, "%lld", YAJL_GET_INTEGER(v)); + len = sprintf(num, "%lld", YAJL_GET_INTEGER(v)); #endif - //else if (YAJL_IS_DOUBLE(v)) // buggy - else if (v->u.number.flags & YAJL_NUMBER_DOUBLE_VALID) - len = sprintf(num, "%g", YAJL_GET_DOUBLE(v)); - else { - num = YAJL_GET_NUMBER(v); - len = strlen(buffer); - } - return yajl_gen_number(g, num, len); - } + //else if (YAJL_IS_DOUBLE(v)) // buggy + else if (v->u.number.flags & YAJL_NUMBER_DOUBLE_VALID) + len = sprintf(num, "%g", YAJL_GET_DOUBLE(v)); + else { + num = YAJL_GET_NUMBER(v); + len = strlen(buffer); + } + return yajl_gen_number(g, num, len); + } - case yajl_t_object: - status = yajl_gen_map_open(g); - if (status != yajl_gen_status_ok) - return status; - - for (size_t i = 0; i < v->u.object.len; i++) { - status = yajl_gen_string(g, (unsigned char *)v->u.object.keys[i], strlen(v->u.object.keys[i])); - if (status != yajl_gen_status_ok) - return status; - status = GenVal(g, v->u.object.values[i]); - if (status != yajl_gen_status_ok) - return status; - } - return yajl_gen_map_close(g); + case yajl_t_object: + status = yajl_gen_map_open(g); + if (status != yajl_gen_status_ok) + return status; + + for (size_t i = 0; i < v->u.object.len; i++) { + status = yajl_gen_string(g, (unsigned char *)v->u.object.keys[i], strlen(v->u.object.keys[i])); + if (status != yajl_gen_status_ok) + return status; + status = GenVal(g, v->u.object.values[i]); + if (status != yajl_gen_status_ok) + return status; + } + return yajl_gen_map_close(g); - case yajl_t_array: - status = yajl_gen_array_open(g); - if (status != yajl_gen_status_ok) - return status; - - for (size_t i = 0; i < v->u.array.len; i++) { - status = GenVal(g, v->u.array.values[i]); - if (status != yajl_gen_status_ok) - return status; - } + case yajl_t_array: + status = yajl_gen_array_open(g); + if (status != yajl_gen_status_ok) + return status; + + for (size_t i = 0; i < v->u.array.len; i++) { + status = GenVal(g, v->u.array.values[i]); + if (status != yajl_gen_status_ok) + return status; + } - return yajl_gen_array_close(g); + return yajl_gen_array_close(g); - case yajl_t_true: return yajl_gen_bool(g, 1); - case yajl_t_false: return yajl_gen_bool(g, 0); - case yajl_t_null: return yajl_gen_null(g); - } - return yajl_gen_in_error_state; + case yajl_t_true: return yajl_gen_bool(g, 1); + case yajl_t_false: return yajl_gen_bool(g, 0); + case yajl_t_null: return yajl_gen_null(g); + } + return yajl_gen_in_error_state; } TEST_F(Yajl, yajl_gen) { - for (int i = 0; i < kTrialCount; i++) { - yajl_gen g = yajl_gen_alloc(NULL); + for (int i = 0; i < kTrialCount; i++) { + yajl_gen g = yajl_gen_alloc(NULL); - yajl_gen_status status = GenVal(g, root_); - if (status != yajl_gen_status_ok) { - std::cout << "gen error: " << status << std::endl; - FAIL(); - } + yajl_gen_status status = GenVal(g, root_); + if (status != yajl_gen_status_ok) { + std::cout << "gen error: " << status << std::endl; + FAIL(); + } - const unsigned char * buf; - size_t len; - status = yajl_gen_get_buf(g, &buf, &len); - ASSERT_EQ(yajl_gen_status_ok, status); - //if (i == 0) - // std::cout << len << std::endl; - yajl_gen_free(g); - } + const unsigned char * buf; + size_t len; + status = yajl_gen_get_buf(g, &buf, &len); + ASSERT_EQ(yajl_gen_status_ok, status); + //if (i == 0) + // std::cout << len << std::endl; + yajl_gen_free(g); + } } TEST_F(Yajl, yajl_gen_beautify) { - for (int i = 0; i < kTrialCount; i++) { - yajl_gen g = yajl_gen_alloc(NULL); - yajl_gen_config(g, yajl_gen_beautify, 1); - yajl_gen_config(g, yajl_gen_indent_string, " "); + for (int i = 0; i < kTrialCount; i++) { + yajl_gen g = yajl_gen_alloc(NULL); + yajl_gen_config(g, yajl_gen_beautify, 1); + yajl_gen_config(g, yajl_gen_indent_string, " "); - yajl_gen_status status = GenVal(g, root_); - if (status != yajl_gen_status_ok) { - std::cout << "gen error: " << status << std::endl; - FAIL(); - } + yajl_gen_status status = GenVal(g, root_); + if (status != yajl_gen_status_ok) { + std::cout << "gen error: " << status << std::endl; + FAIL(); + } - const unsigned char * buf; - size_t len; - status = yajl_gen_get_buf(g, &buf, &len); - ASSERT_EQ(yajl_gen_status_ok, status); - //if (i == 0) - // std::cout << len << std::endl; - yajl_gen_free(g); - } + const unsigned char * buf; + size_t len; + status = yajl_gen_get_buf(g, &buf, &len); + ASSERT_EQ(yajl_gen_status_ok, status); + //if (i == 0) + // std::cout << len << std::endl; + yajl_gen_free(g); + } } TEST_F(Yajl, Whitespace) { - for (int i = 0; i < kTrialCount; i++) { - yajl_val root = yajl_tree_parse(whitespace_, NULL, 0); - ASSERT_TRUE(root != NULL); - yajl_tree_free(root); - } + for (int i = 0; i < kTrialCount; i++) { + yajl_val root = yajl_tree_parse(whitespace_, NULL, 0); + ASSERT_TRUE(root != NULL); + yajl_tree_free(root); + } } #endif // TEST_YAJL diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index fbd035b..0606ccf 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" #include "rapidjson/document.h" #include "rapidjson/writer.h" @@ -9,198 +29,198 @@ using namespace rapidjson; TEST(Document, Parse) { - Document doc; + Document doc; - doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); + doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); - EXPECT_TRUE(doc.IsObject()); + EXPECT_TRUE(doc.IsObject()); - EXPECT_TRUE(doc.HasMember("hello")); - Value& hello = doc["hello"]; - EXPECT_TRUE(hello.IsString()); - EXPECT_STREQ("world", hello.GetString()); + EXPECT_TRUE(doc.HasMember("hello")); + Value& hello = doc["hello"]; + EXPECT_TRUE(hello.IsString()); + EXPECT_STREQ("world", hello.GetString()); - EXPECT_TRUE(doc.HasMember("t")); - Value& t = doc["t"]; - EXPECT_TRUE(t.IsTrue()); + EXPECT_TRUE(doc.HasMember("t")); + Value& t = doc["t"]; + EXPECT_TRUE(t.IsTrue()); - EXPECT_TRUE(doc.HasMember("f")); - Value& f = doc["f"]; - EXPECT_TRUE(f.IsFalse()); + EXPECT_TRUE(doc.HasMember("f")); + Value& f = doc["f"]; + EXPECT_TRUE(f.IsFalse()); - EXPECT_TRUE(doc.HasMember("n")); - Value& n = doc["n"]; - EXPECT_TRUE(n.IsNull()); + EXPECT_TRUE(doc.HasMember("n")); + Value& n = doc["n"]; + EXPECT_TRUE(n.IsNull()); - EXPECT_TRUE(doc.HasMember("i")); - Value& i = doc["i"]; - EXPECT_TRUE(i.IsNumber()); - EXPECT_EQ(123, i.GetInt()); + EXPECT_TRUE(doc.HasMember("i")); + Value& i = doc["i"]; + EXPECT_TRUE(i.IsNumber()); + EXPECT_EQ(123, i.GetInt()); - EXPECT_TRUE(doc.HasMember("pi")); - Value& pi = doc["pi"]; - EXPECT_TRUE(pi.IsNumber()); - EXPECT_EQ(3.1416, pi.GetDouble()); + EXPECT_TRUE(doc.HasMember("pi")); + Value& pi = doc["pi"]; + EXPECT_TRUE(pi.IsNumber()); + EXPECT_EQ(3.1416, pi.GetDouble()); - EXPECT_TRUE(doc.HasMember("a")); - Value& a = doc["a"]; - EXPECT_TRUE(a.IsArray()); - EXPECT_EQ(4u, a.Size()); - for (SizeType i = 0; i < 4; i++) - EXPECT_EQ(i + 1, a[i].GetUint()); + EXPECT_TRUE(doc.HasMember("a")); + Value& a = doc["a"]; + EXPECT_TRUE(a.IsArray()); + EXPECT_EQ(4u, a.Size()); + for (SizeType i = 0; i < 4; i++) + EXPECT_EQ(i + 1, a[i].GetUint()); } static FILE* OpenEncodedFile(const char* filename) { - char buffer[1024]; - sprintf(buffer, "encodings/%s", filename); - FILE *fp = fopen(buffer, "rb"); - if (!fp) { - sprintf(buffer, "../../bin/encodings/%s", filename); - fp = fopen(buffer, "rb"); - } - return fp; + char buffer[1024]; + sprintf(buffer, "encodings/%s", filename); + FILE *fp = fopen(buffer, "rb"); + if (!fp) { + sprintf(buffer, "../../bin/encodings/%s", filename); + fp = fopen(buffer, "rb"); + } + return fp; } TEST(Document, ParseStream_EncodedInputStream) { - // UTF8 -> UTF16 - FILE* fp = OpenEncodedFile("utf8.json"); - char buffer[256]; - FileReadStream bis(fp, buffer, sizeof(buffer)); - EncodedInputStream, FileReadStream> eis(bis); + // UTF8 -> UTF16 + FILE* fp = OpenEncodedFile("utf8.json"); + char buffer[256]; + FileReadStream bis(fp, buffer, sizeof(buffer)); + EncodedInputStream, FileReadStream> eis(bis); - GenericDocument > d; - d.ParseStream<0, UTF8<> >(eis); - EXPECT_FALSE(d.HasParseError()); + GenericDocument > d; + d.ParseStream<0, UTF8<> >(eis); + EXPECT_FALSE(d.HasParseError()); - fclose(fp); + fclose(fp); - wchar_t expected[] = L"I can eat glass and it doesn't hurt me."; - GenericValue >& v = d[L"en"]; - EXPECT_TRUE(v.IsString()); - EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength()); - EXPECT_EQ(0, StrCmp(expected, v.GetString())); + wchar_t expected[] = L"I can eat glass and it doesn't hurt me."; + GenericValue >& v = d[L"en"]; + EXPECT_TRUE(v.IsString()); + EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength()); + EXPECT_EQ(0, StrCmp(expected, v.GetString())); - // UTF16 -> UTF8 in memory - StringBuffer bos; - typedef EncodedOutputStream, StringBuffer> OutputStream; - OutputStream eos(bos, false); // Not writing BOM - Writer, UTF8<> > writer(eos); - d.Accept(writer); + // UTF16 -> UTF8 in memory + StringBuffer bos; + typedef EncodedOutputStream, StringBuffer> OutputStream; + OutputStream eos(bos, false); // Not writing BOM + Writer, UTF8<> > writer(eos); + d.Accept(writer); - { - // Condense the original file and compare. - FILE *fp = OpenEncodedFile("utf8.json"); - FileReadStream is(fp, buffer, sizeof(buffer)); - Reader reader; - StringBuffer bos2; - Writer writer(bos2); - reader.Parse(is, writer); + { + // Condense the original file and compare. + FILE *fp = OpenEncodedFile("utf8.json"); + FileReadStream is(fp, buffer, sizeof(buffer)); + Reader reader; + StringBuffer bos2; + Writer writer(bos2); + reader.Parse(is, writer); - EXPECT_EQ(bos.GetSize(), bos2.GetSize()); - EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); - } + EXPECT_EQ(bos.GetSize(), bos2.GetSize()); + EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); + } } TEST(Document, ParseStream_AutoUTFInputStream) { - // Any -> UTF8 - FILE* fp = OpenEncodedFile("utf32be.json"); - char buffer[256]; - FileReadStream bis(fp, buffer, sizeof(buffer)); - AutoUTFInputStream eis(bis); + // Any -> UTF8 + FILE* fp = OpenEncodedFile("utf32be.json"); + char buffer[256]; + FileReadStream bis(fp, buffer, sizeof(buffer)); + AutoUTFInputStream eis(bis); - Document d; - d.ParseStream<0, AutoUTF >(eis); - EXPECT_FALSE(d.HasParseError()); + Document d; + d.ParseStream<0, AutoUTF >(eis); + EXPECT_FALSE(d.HasParseError()); - fclose(fp); + fclose(fp); - char expected[] = "I can eat glass and it doesn't hurt me."; - Value& v = d["en"]; - EXPECT_TRUE(v.IsString()); - EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength()); - EXPECT_EQ(0, StrCmp(expected, v.GetString())); + char expected[] = "I can eat glass and it doesn't hurt me."; + Value& v = d["en"]; + EXPECT_TRUE(v.IsString()); + EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength()); + EXPECT_EQ(0, StrCmp(expected, v.GetString())); - // UTF8 -> UTF8 in memory - StringBuffer bos; - Writer writer(bos); - d.Accept(writer); + // UTF8 -> UTF8 in memory + StringBuffer bos; + Writer writer(bos); + d.Accept(writer); - { - // Condense the original file and compare. - FILE *fp = OpenEncodedFile("utf8.json"); - FileReadStream is(fp, buffer, sizeof(buffer)); - Reader reader; - StringBuffer bos2; - Writer writer(bos2); - reader.Parse(is, writer); + { + // Condense the original file and compare. + FILE *fp = OpenEncodedFile("utf8.json"); + FileReadStream is(fp, buffer, sizeof(buffer)); + Reader reader; + StringBuffer bos2; + Writer writer(bos2); + reader.Parse(is, writer); - EXPECT_EQ(bos.GetSize(), bos2.GetSize()); - EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); - } + EXPECT_EQ(bos.GetSize(), bos2.GetSize()); + EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize())); + } } TEST(Document, Swap) { - Document d1; - Document::AllocatorType& a = d1.GetAllocator(); + Document d1; + Document::AllocatorType& a = d1.GetAllocator(); - d1.SetArray().PushBack(1, a).PushBack(2, a); + d1.SetArray().PushBack(1, a).PushBack(2, a); - Value o; - o.SetObject().AddMember("a", 1, a); + Value o; + o.SetObject().AddMember("a", 1, a); - // Swap between Document and Value - d1.Swap(o); - EXPECT_TRUE(d1.IsObject()); - EXPECT_TRUE(o.IsArray()); + // Swap between Document and Value + d1.Swap(o); + EXPECT_TRUE(d1.IsObject()); + EXPECT_TRUE(o.IsArray()); - // Swap between Document and Document - Document d2; - d2.SetArray().PushBack(3, a); - d1.Swap(d2); - EXPECT_TRUE(d1.IsArray()); - EXPECT_TRUE(d2.IsObject()); + // Swap between Document and Document + Document d2; + d2.SetArray().PushBack(3, a); + d1.Swap(d2); + EXPECT_TRUE(d1.IsArray()); + EXPECT_TRUE(d2.IsObject()); } // This should be slow due to assignment in inner-loop. struct OutputStringStream : public std::ostringstream { - typedef char Ch; + typedef char Ch; - void Put(char c) { - put(c); - } - void Flush() {} + void Put(char c) { + put(c); + } + void Flush() {} }; TEST(Document, AcceptWriter) { - Document doc; - doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); + Document doc; + doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); - OutputStringStream os; - Writer writer(os); - doc.Accept(writer); + OutputStringStream os; + Writer writer(os); + doc.Accept(writer); - EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str()); + EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str()); } -// Issue 44: SetStringRaw doesn't work with wchar_t +// Issue 44: SetStringRaw doesn't work with wchar_t TEST(Document, UTF16_Document) { - GenericDocument< UTF16<> > json; - json.Parse(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]"); + GenericDocument< UTF16<> > json; + json.Parse(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]"); - ASSERT_TRUE(json.IsArray()); - GenericValue< UTF16<> >& v = json[0u]; - ASSERT_TRUE(v.IsObject()); + ASSERT_TRUE(json.IsArray()); + GenericValue< UTF16<> >& v = json[0u]; + ASSERT_TRUE(v.IsObject()); - GenericValue< UTF16<> >& s = v[L"created_at"]; - ASSERT_TRUE(s.IsString()); + GenericValue< UTF16<> >& s = v[L"created_at"]; + ASSERT_TRUE(s.IsString()); - EXPECT_EQ(0, wcscmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString())); + EXPECT_EQ(0, wcscmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString())); } // Issue 22: Memory corruption via operator= // Fixed by making unimplemented assignment operator private. //TEST(Document, Assignment) { -// Document d1; -// Document d2; -// d1 = d2; +// Document d1; +// Document d2; +// d1 = d2; //} diff --git a/test/unittest/encodedstreamtest.cpp b/test/unittest/encodedstreamtest.cpp index 4e4db2d..a29cb3b 100644 --- a/test/unittest/encodedstreamtest.cpp +++ b/test/unittest/encodedstreamtest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" #include "rapidjson/filereadstream.h" #include "rapidjson/filewritestream.h" @@ -10,270 +30,270 @@ using namespace rapidjson; class EncodedStreamTest : public ::testing::Test { public: - EncodedStreamTest() : json_(), length_() {} + EncodedStreamTest() : json_(), length_() {} - virtual void SetUp() { - json_ = ReadFile("utf8.json", true, &length_); - } + virtual void SetUp() { + json_ = ReadFile("utf8.json", true, &length_); + } - virtual void TearDown() { - free(json_); - json_ = 0; - } + virtual void TearDown() { + free(json_); + json_ = 0; + } private: - EncodedStreamTest(const EncodedStreamTest&); - EncodedStreamTest& operator=(const EncodedStreamTest&); - + EncodedStreamTest(const EncodedStreamTest&); + EncodedStreamTest& operator=(const EncodedStreamTest&); + protected: - static FILE* Open(const char* filename) { - char buffer[1024]; - sprintf(buffer, "encodings/%s", filename); - FILE *fp = fopen(buffer, "rb"); - if (!fp) { - sprintf(buffer, "../../bin/encodings/%s", filename); - fp = fopen(buffer, "rb"); - } - return fp; - } + static FILE* Open(const char* filename) { + char buffer[1024]; + sprintf(buffer, "encodings/%s", filename); + FILE *fp = fopen(buffer, "rb"); + if (!fp) { + sprintf(buffer, "../../bin/encodings/%s", filename); + fp = fopen(buffer, "rb"); + } + return fp; + } - static char *ReadFile(const char* filename, bool appendPath, size_t* outLength) { - FILE *fp = appendPath ? Open(filename) : fopen(filename, "rb"); + static char *ReadFile(const char* filename, bool appendPath, size_t* outLength) { + FILE *fp = appendPath ? Open(filename) : fopen(filename, "rb"); - if (!fp) { - *outLength = 0; - return 0; - } + if (!fp) { + *outLength = 0; + return 0; + } - fseek(fp, 0, SEEK_END); - *outLength = (size_t)ftell(fp); - fseek(fp, 0, SEEK_SET); - char* buffer = (char*)malloc(*outLength + 1); - size_t readLength = fread(buffer, 1, *outLength, fp); - buffer[readLength] = '\0'; - fclose(fp); - return buffer; - } + fseek(fp, 0, SEEK_END); + *outLength = (size_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + char* buffer = (char*)malloc(*outLength + 1); + size_t readLength = fread(buffer, 1, *outLength, fp); + buffer[readLength] = '\0'; + fclose(fp); + return buffer; + } - template - void TestEncodedInputStream(const char* filename) { - // Test FileReadStream - { - char buffer[16]; - FILE *fp = Open(filename); - ASSERT_TRUE(fp != 0); - FileReadStream fs(fp, buffer, sizeof(buffer)); - EncodedInputStream eis(fs); - StringStream s(json_); + template + void TestEncodedInputStream(const char* filename) { + // Test FileReadStream + { + char buffer[16]; + FILE *fp = Open(filename); + ASSERT_TRUE(fp != 0); + FileReadStream fs(fp, buffer, sizeof(buffer)); + EncodedInputStream eis(fs); + StringStream s(json_); - while (eis.Peek() != '\0') { - unsigned expected, actual; - EXPECT_TRUE(UTF8<>::Decode(s, &expected)); - EXPECT_TRUE(MemoryEncoding::Decode(eis, &actual)); - EXPECT_EQ(expected, actual); - } - EXPECT_EQ('\0', s.Peek()); - fclose(fp); - } + while (eis.Peek() != '\0') { + unsigned expected, actual; + EXPECT_TRUE(UTF8<>::Decode(s, &expected)); + EXPECT_TRUE(MemoryEncoding::Decode(eis, &actual)); + EXPECT_EQ(expected, actual); + } + EXPECT_EQ('\0', s.Peek()); + fclose(fp); + } - // Test MemoryStream - { - size_t size; - char* data = ReadFile(filename, true, &size); - MemoryStream ms(data, size); - EncodedInputStream eis(ms); - StringStream s(json_); + // Test MemoryStream + { + size_t size; + char* data = ReadFile(filename, true, &size); + MemoryStream ms(data, size); + EncodedInputStream eis(ms); + StringStream s(json_); - while (eis.Peek() != '\0') { - unsigned expected, actual; - EXPECT_TRUE(UTF8<>::Decode(s, &expected)); - EXPECT_TRUE(MemoryEncoding::Decode(eis, &actual)); - EXPECT_EQ(expected, actual); - } - EXPECT_EQ('\0', s.Peek()); - free(data); - } - } + while (eis.Peek() != '\0') { + unsigned expected, actual; + EXPECT_TRUE(UTF8<>::Decode(s, &expected)); + EXPECT_TRUE(MemoryEncoding::Decode(eis, &actual)); + EXPECT_EQ(expected, actual); + } + EXPECT_EQ('\0', s.Peek()); + free(data); + } + } - void TestAutoUTFInputStream(const char *filename) { - // Test FileReadStream - { - char buffer[16]; - FILE *fp = Open(filename); - ASSERT_TRUE(fp != 0); - FileReadStream fs(fp, buffer, sizeof(buffer)); - AutoUTFInputStream eis(fs); - StringStream s(json_); - while (eis.Peek() != '\0') { - unsigned expected, actual; - EXPECT_TRUE(UTF8<>::Decode(s, &expected)); - EXPECT_TRUE(AutoUTF::Decode(eis, &actual)); - EXPECT_EQ(expected, actual); - } - EXPECT_EQ('\0', s.Peek()); - fclose(fp); - } + void TestAutoUTFInputStream(const char *filename) { + // Test FileReadStream + { + char buffer[16]; + FILE *fp = Open(filename); + ASSERT_TRUE(fp != 0); + FileReadStream fs(fp, buffer, sizeof(buffer)); + AutoUTFInputStream eis(fs); + StringStream s(json_); + while (eis.Peek() != '\0') { + unsigned expected, actual; + EXPECT_TRUE(UTF8<>::Decode(s, &expected)); + EXPECT_TRUE(AutoUTF::Decode(eis, &actual)); + EXPECT_EQ(expected, actual); + } + EXPECT_EQ('\0', s.Peek()); + fclose(fp); + } - // Test MemoryStream - { - size_t size; - char* data = ReadFile(filename, true, &size); - MemoryStream ms(data, size); - AutoUTFInputStream eis(ms); - StringStream s(json_); + // Test MemoryStream + { + size_t size; + char* data = ReadFile(filename, true, &size); + MemoryStream ms(data, size); + AutoUTFInputStream eis(ms); + StringStream s(json_); - while (eis.Peek() != '\0') { - unsigned expected, actual; - EXPECT_TRUE(UTF8<>::Decode(s, &expected)); - EXPECT_TRUE(AutoUTF::Decode(eis, &actual)); - EXPECT_EQ(expected, actual); - } - EXPECT_EQ('\0', s.Peek()); - free(data); - } - } + while (eis.Peek() != '\0') { + unsigned expected, actual; + EXPECT_TRUE(UTF8<>::Decode(s, &expected)); + EXPECT_TRUE(AutoUTF::Decode(eis, &actual)); + EXPECT_EQ(expected, actual); + } + EXPECT_EQ('\0', s.Peek()); + free(data); + } + } - template - void TestEncodedOutputStream(const char* expectedFilename, bool putBOM) { - // Test FileWriteStream - { - char filename[L_tmpnam]; - TempFilename(filename); + template + void TestEncodedOutputStream(const char* expectedFilename, bool putBOM) { + // Test FileWriteStream + { + char filename[L_tmpnam]; + TempFilename(filename); - FILE *fp = fopen(filename, "wb"); - char buffer[16]; - FileWriteStream os(fp, buffer, sizeof(buffer)); - EncodedOutputStream eos(os, putBOM); - StringStream s(json_); - while (s.Peek() != '\0') { - bool success = Transcoder, MemoryEncoding>::Transcode(s, eos); - EXPECT_TRUE(success); - } - eos.Flush(); - fclose(fp); - EXPECT_TRUE(CompareFile(filename, expectedFilename)); - remove(filename); - } + FILE *fp = fopen(filename, "wb"); + char buffer[16]; + FileWriteStream os(fp, buffer, sizeof(buffer)); + EncodedOutputStream eos(os, putBOM); + StringStream s(json_); + while (s.Peek() != '\0') { + bool success = Transcoder, MemoryEncoding>::Transcode(s, eos); + EXPECT_TRUE(success); + } + eos.Flush(); + fclose(fp); + EXPECT_TRUE(CompareFile(filename, expectedFilename)); + remove(filename); + } - // Test MemoryBuffer - { - MemoryBuffer mb; - EncodedOutputStream eos(mb, putBOM); - StringStream s(json_); - while (s.Peek() != '\0') { - bool success = Transcoder, MemoryEncoding>::Transcode(s, eos); - EXPECT_TRUE(success); - } - eos.Flush(); - EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename)); - } - } + // Test MemoryBuffer + { + MemoryBuffer mb; + EncodedOutputStream eos(mb, putBOM); + StringStream s(json_); + while (s.Peek() != '\0') { + bool success = Transcoder, MemoryEncoding>::Transcode(s, eos); + EXPECT_TRUE(success); + } + eos.Flush(); + EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename)); + } + } - void TestAutoUTFOutputStream(UTFType type, bool putBOM, const char *expectedFilename) { - // Test FileWriteStream - { - char filename[L_tmpnam]; - TempFilename(filename); + void TestAutoUTFOutputStream(UTFType type, bool putBOM, const char *expectedFilename) { + // Test FileWriteStream + { + char filename[L_tmpnam]; + TempFilename(filename); - FILE *fp = fopen(filename, "wb"); - char buffer[16]; - FileWriteStream os(fp, buffer, sizeof(buffer)); - AutoUTFOutputStream eos(os, type, putBOM); - StringStream s(json_); - while (s.Peek() != '\0') { - bool success = Transcoder, AutoUTF >::Transcode(s, eos); - EXPECT_TRUE(success); - } - eos.Flush(); - fclose(fp); - EXPECT_TRUE(CompareFile(filename, expectedFilename)); - remove(filename); - } + FILE *fp = fopen(filename, "wb"); + char buffer[16]; + FileWriteStream os(fp, buffer, sizeof(buffer)); + AutoUTFOutputStream eos(os, type, putBOM); + StringStream s(json_); + while (s.Peek() != '\0') { + bool success = Transcoder, AutoUTF >::Transcode(s, eos); + EXPECT_TRUE(success); + } + eos.Flush(); + fclose(fp); + EXPECT_TRUE(CompareFile(filename, expectedFilename)); + remove(filename); + } - // Test MemoryBuffer - { - MemoryBuffer mb; - AutoUTFOutputStream eos(mb, type, putBOM); - StringStream s(json_); - while (s.Peek() != '\0') { - bool success = Transcoder, AutoUTF >::Transcode(s, eos); - EXPECT_TRUE(success); - } - eos.Flush(); - EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename)); - } - } + // Test MemoryBuffer + { + MemoryBuffer mb; + AutoUTFOutputStream eos(mb, type, putBOM); + StringStream s(json_); + while (s.Peek() != '\0') { + bool success = Transcoder, AutoUTF >::Transcode(s, eos); + EXPECT_TRUE(success); + } + eos.Flush(); + EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename)); + } + } - bool CompareFile(const char* filename, const char* expectedFilename) { - size_t actualLength, expectedLength; - char* actualBuffer = ReadFile(filename, false, &actualLength); - char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength); - bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0; - free(actualBuffer); - free(expectedBuffer); - return ret; - } + bool CompareFile(const char* filename, const char* expectedFilename) { + size_t actualLength, expectedLength; + char* actualBuffer = ReadFile(filename, false, &actualLength); + char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength); + bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0; + free(actualBuffer); + free(expectedBuffer); + return ret; + } - bool CompareBufferFile(const char* actualBuffer, size_t actualLength, const char* expectedFilename) { - size_t expectedLength; - char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength); - bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0; - free(expectedBuffer); - return ret; - } + bool CompareBufferFile(const char* actualBuffer, size_t actualLength, const char* expectedFilename) { + size_t expectedLength; + char* expectedBuffer = ReadFile(expectedFilename, true, &expectedLength); + bool ret = (expectedLength == actualLength) && memcmp(expectedBuffer, actualBuffer, actualLength) == 0; + free(expectedBuffer); + return ret; + } - char *json_; - size_t length_; + char *json_; + size_t length_; }; TEST_F(EncodedStreamTest, EncodedInputStream) { - TestEncodedInputStream, UTF8<> >("utf8.json"); - TestEncodedInputStream, UTF8<> >("utf8bom.json"); - TestEncodedInputStream, UTF16<> >("utf16le.json"); - TestEncodedInputStream, UTF16<> >("utf16lebom.json"); - TestEncodedInputStream, UTF16<> >("utf16be.json"); - TestEncodedInputStream, UTF16<> >("utf16bebom.json"); - TestEncodedInputStream, UTF32<> >("utf32le.json"); - TestEncodedInputStream, UTF32<> >("utf32lebom.json"); - TestEncodedInputStream, UTF32<> >("utf32be.json"); - TestEncodedInputStream, UTF32<> >("utf32bebom.json"); + TestEncodedInputStream, UTF8<> >("utf8.json"); + TestEncodedInputStream, UTF8<> >("utf8bom.json"); + TestEncodedInputStream, UTF16<> >("utf16le.json"); + TestEncodedInputStream, UTF16<> >("utf16lebom.json"); + TestEncodedInputStream, UTF16<> >("utf16be.json"); + TestEncodedInputStream, UTF16<> >("utf16bebom.json"); + TestEncodedInputStream, UTF32<> >("utf32le.json"); + TestEncodedInputStream, UTF32<> >("utf32lebom.json"); + TestEncodedInputStream, UTF32<> >("utf32be.json"); + TestEncodedInputStream, UTF32<> >("utf32bebom.json"); } TEST_F(EncodedStreamTest, AutoUTFInputStream) { - TestAutoUTFInputStream("utf8.json"); - TestAutoUTFInputStream("utf8bom.json"); - TestAutoUTFInputStream("utf16le.json"); - TestAutoUTFInputStream("utf16lebom.json"); - TestAutoUTFInputStream("utf16be.json"); - TestAutoUTFInputStream("utf16bebom.json"); - TestAutoUTFInputStream("utf32le.json"); - TestAutoUTFInputStream("utf32lebom.json"); - TestAutoUTFInputStream("utf32be.json"); - TestAutoUTFInputStream("utf32bebom.json"); + TestAutoUTFInputStream("utf8.json"); + TestAutoUTFInputStream("utf8bom.json"); + TestAutoUTFInputStream("utf16le.json"); + TestAutoUTFInputStream("utf16lebom.json"); + TestAutoUTFInputStream("utf16be.json"); + TestAutoUTFInputStream("utf16bebom.json"); + TestAutoUTFInputStream("utf32le.json"); + TestAutoUTFInputStream("utf32lebom.json"); + TestAutoUTFInputStream("utf32be.json"); + TestAutoUTFInputStream("utf32bebom.json"); } TEST_F(EncodedStreamTest, EncodedOutputStream) { - TestEncodedOutputStream, UTF8<> >("utf8.json", false); - TestEncodedOutputStream, UTF8<> >("utf8bom.json", true); - TestEncodedOutputStream, UTF16<> >("utf16le.json", false); - TestEncodedOutputStream, UTF16<> >("utf16lebom.json",true); - TestEncodedOutputStream, UTF16<> >("utf16be.json", false); - TestEncodedOutputStream, UTF16<> >("utf16bebom.json",true); - TestEncodedOutputStream, UTF32<> >("utf32le.json", false); - TestEncodedOutputStream, UTF32<> >("utf32lebom.json",true); - TestEncodedOutputStream, UTF32<> >("utf32be.json", false); - TestEncodedOutputStream, UTF32<> >("utf32bebom.json",true); + TestEncodedOutputStream, UTF8<> >("utf8.json", false); + TestEncodedOutputStream, UTF8<> >("utf8bom.json", true); + TestEncodedOutputStream, UTF16<> >("utf16le.json", false); + TestEncodedOutputStream, UTF16<> >("utf16lebom.json",true); + TestEncodedOutputStream, UTF16<> >("utf16be.json", false); + TestEncodedOutputStream, UTF16<> >("utf16bebom.json",true); + TestEncodedOutputStream, UTF32<> >("utf32le.json", false); + TestEncodedOutputStream, UTF32<> >("utf32lebom.json",true); + TestEncodedOutputStream, UTF32<> >("utf32be.json", false); + TestEncodedOutputStream, UTF32<> >("utf32bebom.json",true); } TEST_F(EncodedStreamTest, AutoUTFOutputStream) { - TestAutoUTFOutputStream(kUTF8, false, "utf8.json"); - TestAutoUTFOutputStream(kUTF8, true, "utf8bom.json"); - TestAutoUTFOutputStream(kUTF16LE, false, "utf16le.json"); - TestAutoUTFOutputStream(kUTF16LE, true, "utf16lebom.json"); - TestAutoUTFOutputStream(kUTF16BE, false, "utf16be.json"); - TestAutoUTFOutputStream(kUTF16BE, true, "utf16bebom.json"); - TestAutoUTFOutputStream(kUTF32LE, false, "utf32le.json"); - TestAutoUTFOutputStream(kUTF32LE, true, "utf32lebom.json"); - TestAutoUTFOutputStream(kUTF32BE, false, "utf32be.json"); - TestAutoUTFOutputStream(kUTF32BE, true, "utf32bebom.json"); + TestAutoUTFOutputStream(kUTF8, false, "utf8.json"); + TestAutoUTFOutputStream(kUTF8, true, "utf8bom.json"); + TestAutoUTFOutputStream(kUTF16LE, false, "utf16le.json"); + TestAutoUTFOutputStream(kUTF16LE, true, "utf16lebom.json"); + TestAutoUTFOutputStream(kUTF16BE, false, "utf16be.json"); + TestAutoUTFOutputStream(kUTF16BE, true, "utf16bebom.json"); + TestAutoUTFOutputStream(kUTF32LE, false, "utf32le.json"); + TestAutoUTFOutputStream(kUTF32LE, true, "utf32lebom.json"); + TestAutoUTFOutputStream(kUTF32BE, false, "utf32be.json"); + TestAutoUTFOutputStream(kUTF32BE, true, "utf32bebom.json"); } diff --git a/test/unittest/encodingstest.cpp b/test/unittest/encodingstest.cpp index 86c7d6e..3beebe6 100644 --- a/test/unittest/encodingstest.cpp +++ b/test/unittest/encodingstest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" #include "rapidjson/filereadstream.h" #include "rapidjson/filewritestream.h" @@ -10,216 +30,216 @@ using namespace rapidjson; // http://www.unicode.org/Public/UNIDATA/Blocks.txt static const unsigned kCodepointRanges[] = { - 0x0000, 0x007F, // Basic Latin - 0x0080, 0x00FF, // Latin-1 Supplement - 0x0100, 0x017F, // Latin Extended-A - 0x0180, 0x024F, // Latin Extended-B - 0x0250, 0x02AF, // IPA Extensions - 0x02B0, 0x02FF, // Spacing Modifier Letters - 0x0300, 0x036F, // Combining Diacritical Marks - 0x0370, 0x03FF, // Greek and Coptic - 0x0400, 0x04FF, // Cyrillic - 0x0500, 0x052F, // Cyrillic Supplement - 0x0530, 0x058F, // Armenian - 0x0590, 0x05FF, // Hebrew - 0x0600, 0x06FF, // Arabic - 0x0700, 0x074F, // Syriac - 0x0750, 0x077F, // Arabic Supplement - 0x0780, 0x07BF, // Thaana - 0x07C0, 0x07FF, // NKo - 0x0800, 0x083F, // Samaritan - 0x0840, 0x085F, // Mandaic - 0x0900, 0x097F, // Devanagari - 0x0980, 0x09FF, // Bengali - 0x0A00, 0x0A7F, // Gurmukhi - 0x0A80, 0x0AFF, // Gujarati - 0x0B00, 0x0B7F, // Oriya - 0x0B80, 0x0BFF, // Tamil - 0x0C00, 0x0C7F, // Telugu - 0x0C80, 0x0CFF, // Kannada - 0x0D00, 0x0D7F, // Malayalam - 0x0D80, 0x0DFF, // Sinhala - 0x0E00, 0x0E7F, // Thai - 0x0E80, 0x0EFF, // Lao - 0x0F00, 0x0FFF, // Tibetan - 0x1000, 0x109F, // Myanmar - 0x10A0, 0x10FF, // Georgian - 0x1100, 0x11FF, // Hangul Jamo - 0x1200, 0x137F, // Ethiopic - 0x1380, 0x139F, // Ethiopic Supplement - 0x13A0, 0x13FF, // Cherokee - 0x1400, 0x167F, // Unified Canadian Aboriginal Syllabics - 0x1680, 0x169F, // Ogham - 0x16A0, 0x16FF, // Runic - 0x1700, 0x171F, // Tagalog - 0x1720, 0x173F, // Hanunoo - 0x1740, 0x175F, // Buhid - 0x1760, 0x177F, // Tagbanwa - 0x1780, 0x17FF, // Khmer - 0x1800, 0x18AF, // Mongolian - 0x18B0, 0x18FF, // Unified Canadian Aboriginal Syllabics Extended - 0x1900, 0x194F, // Limbu - 0x1950, 0x197F, // Tai Le - 0x1980, 0x19DF, // New Tai Lue - 0x19E0, 0x19FF, // Khmer Symbols - 0x1A00, 0x1A1F, // Buginese - 0x1A20, 0x1AAF, // Tai Tham - 0x1B00, 0x1B7F, // Balinese - 0x1B80, 0x1BBF, // Sundanese - 0x1BC0, 0x1BFF, // Batak - 0x1C00, 0x1C4F, // Lepcha - 0x1C50, 0x1C7F, // Ol Chiki - 0x1CD0, 0x1CFF, // Vedic Extensions - 0x1D00, 0x1D7F, // Phonetic Extensions - 0x1D80, 0x1DBF, // Phonetic Extensions Supplement - 0x1DC0, 0x1DFF, // Combining Diacritical Marks Supplement - 0x1E00, 0x1EFF, // Latin Extended Additional - 0x1F00, 0x1FFF, // Greek Extended - 0x2000, 0x206F, // General Punctuation - 0x2070, 0x209F, // Superscripts and Subscripts - 0x20A0, 0x20CF, // Currency Symbols - 0x20D0, 0x20FF, // Combining Diacritical Marks for Symbols - 0x2100, 0x214F, // Letterlike Symbols - 0x2150, 0x218F, // Number Forms - 0x2190, 0x21FF, // Arrows - 0x2200, 0x22FF, // Mathematical Operators - 0x2300, 0x23FF, // Miscellaneous Technical - 0x2400, 0x243F, // Control Pictures - 0x2440, 0x245F, // Optical Character Recognition - 0x2460, 0x24FF, // Enclosed Alphanumerics - 0x2500, 0x257F, // Box Drawing - 0x2580, 0x259F, // Block Elements - 0x25A0, 0x25FF, // Geometric Shapes - 0x2600, 0x26FF, // Miscellaneous Symbols - 0x2700, 0x27BF, // Dingbats - 0x27C0, 0x27EF, // Miscellaneous Mathematical Symbols-A - 0x27F0, 0x27FF, // Supplemental Arrows-A - 0x2800, 0x28FF, // Braille Patterns - 0x2900, 0x297F, // Supplemental Arrows-B - 0x2980, 0x29FF, // Miscellaneous Mathematical Symbols-B - 0x2A00, 0x2AFF, // Supplemental Mathematical Operators - 0x2B00, 0x2BFF, // Miscellaneous Symbols and Arrows - 0x2C00, 0x2C5F, // Glagolitic - 0x2C60, 0x2C7F, // Latin Extended-C - 0x2C80, 0x2CFF, // Coptic - 0x2D00, 0x2D2F, // Georgian Supplement - 0x2D30, 0x2D7F, // Tifinagh - 0x2D80, 0x2DDF, // Ethiopic Extended - 0x2DE0, 0x2DFF, // Cyrillic Extended-A - 0x2E00, 0x2E7F, // Supplemental Punctuation - 0x2E80, 0x2EFF, // CJK Radicals Supplement - 0x2F00, 0x2FDF, // Kangxi Radicals - 0x2FF0, 0x2FFF, // Ideographic Description Characters - 0x3000, 0x303F, // CJK Symbols and Punctuation - 0x3040, 0x309F, // Hiragana - 0x30A0, 0x30FF, // Katakana - 0x3100, 0x312F, // Bopomofo - 0x3130, 0x318F, // Hangul Compatibility Jamo - 0x3190, 0x319F, // Kanbun - 0x31A0, 0x31BF, // Bopomofo Extended - 0x31C0, 0x31EF, // CJK Strokes - 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0x3200, 0x32FF, // Enclosed CJK Letters and Months - 0x3300, 0x33FF, // CJK Compatibility - 0x3400, 0x4DBF, // CJK Unified Ideographs Extension A - 0x4DC0, 0x4DFF, // Yijing Hexagram Symbols - 0x4E00, 0x9FFF, // CJK Unified Ideographs - 0xA000, 0xA48F, // Yi Syllables - 0xA490, 0xA4CF, // Yi Radicals - 0xA4D0, 0xA4FF, // Lisu - 0xA500, 0xA63F, // Vai - 0xA640, 0xA69F, // Cyrillic Extended-B - 0xA6A0, 0xA6FF, // Bamum - 0xA700, 0xA71F, // Modifier Tone Letters - 0xA720, 0xA7FF, // Latin Extended-D - 0xA800, 0xA82F, // Syloti Nagri - 0xA830, 0xA83F, // Common Indic Number Forms - 0xA840, 0xA87F, // Phags-pa - 0xA880, 0xA8DF, // Saurashtra - 0xA8E0, 0xA8FF, // Devanagari Extended - 0xA900, 0xA92F, // Kayah Li - 0xA930, 0xA95F, // Rejang - 0xA960, 0xA97F, // Hangul Jamo Extended-A - 0xA980, 0xA9DF, // Javanese - 0xAA00, 0xAA5F, // Cham - 0xAA60, 0xAA7F, // Myanmar Extended-A - 0xAA80, 0xAADF, // Tai Viet - 0xAB00, 0xAB2F, // Ethiopic Extended-A - 0xABC0, 0xABFF, // Meetei Mayek - 0xAC00, 0xD7AF, // Hangul Syllables - 0xD7B0, 0xD7FF, // Hangul Jamo Extended-B - //0xD800, 0xDB7F, // High Surrogates - //0xDB80, 0xDBFF, // High Private Use Surrogates - //0xDC00, 0xDFFF, // Low Surrogates - 0xE000, 0xF8FF, // Private Use Area - 0xF900, 0xFAFF, // CJK Compatibility Ideographs - 0xFB00, 0xFB4F, // Alphabetic Presentation Forms - 0xFB50, 0xFDFF, // Arabic Presentation Forms-A - 0xFE00, 0xFE0F, // Variation Selectors - 0xFE10, 0xFE1F, // Vertical Forms - 0xFE20, 0xFE2F, // Combining Half Marks - 0xFE30, 0xFE4F, // CJK Compatibility Forms - 0xFE50, 0xFE6F, // Small Form Variants - 0xFE70, 0xFEFF, // Arabic Presentation Forms-B - 0xFF00, 0xFFEF, // Halfwidth and Fullwidth Forms - 0xFFF0, 0xFFFF, // Specials - 0x10000, 0x1007F, // Linear B Syllabary - 0x10080, 0x100FF, // Linear B Ideograms - 0x10100, 0x1013F, // Aegean Numbers - 0x10140, 0x1018F, // Ancient Greek Numbers - 0x10190, 0x101CF, // Ancient Symbols - 0x101D0, 0x101FF, // Phaistos Disc - 0x10280, 0x1029F, // Lycian - 0x102A0, 0x102DF, // Carian - 0x10300, 0x1032F, // Old Italic - 0x10330, 0x1034F, // Gothic - 0x10380, 0x1039F, // Ugaritic - 0x103A0, 0x103DF, // Old Persian - 0x10400, 0x1044F, // Deseret - 0x10450, 0x1047F, // Shavian - 0x10480, 0x104AF, // Osmanya - 0x10800, 0x1083F, // Cypriot Syllabary - 0x10840, 0x1085F, // Imperial Aramaic - 0x10900, 0x1091F, // Phoenician - 0x10920, 0x1093F, // Lydian - 0x10A00, 0x10A5F, // Kharoshthi - 0x10A60, 0x10A7F, // Old South Arabian - 0x10B00, 0x10B3F, // Avestan - 0x10B40, 0x10B5F, // Inscriptional Parthian - 0x10B60, 0x10B7F, // Inscriptional Pahlavi - 0x10C00, 0x10C4F, // Old Turkic - 0x10E60, 0x10E7F, // Rumi Numeral Symbols - 0x11000, 0x1107F, // Brahmi - 0x11080, 0x110CF, // Kaithi - 0x12000, 0x123FF, // Cuneiform - 0x12400, 0x1247F, // Cuneiform Numbers and Punctuation - 0x13000, 0x1342F, // Egyptian Hieroglyphs - 0x16800, 0x16A3F, // Bamum Supplement - 0x1B000, 0x1B0FF, // Kana Supplement - 0x1D000, 0x1D0FF, // Byzantine Musical Symbols - 0x1D100, 0x1D1FF, // Musical Symbols - 0x1D200, 0x1D24F, // Ancient Greek Musical Notation - 0x1D300, 0x1D35F, // Tai Xuan Jing Symbols - 0x1D360, 0x1D37F, // Counting Rod Numerals - 0x1D400, 0x1D7FF, // Mathematical Alphanumeric Symbols - 0x1F000, 0x1F02F, // Mahjong Tiles - 0x1F030, 0x1F09F, // Domino Tiles - 0x1F0A0, 0x1F0FF, // Playing Cards - 0x1F100, 0x1F1FF, // Enclosed Alphanumeric Supplement - 0x1F200, 0x1F2FF, // Enclosed Ideographic Supplement - 0x1F300, 0x1F5FF, // Miscellaneous Symbols And Pictographs - 0x1F600, 0x1F64F, // Emoticons - 0x1F680, 0x1F6FF, // Transport And Map Symbols - 0x1F700, 0x1F77F, // Alchemical Symbols - 0x20000, 0x2A6DF, // CJK Unified Ideographs Extension B - 0x2A700, 0x2B73F, // CJK Unified Ideographs Extension C - 0x2B740, 0x2B81F, // CJK Unified Ideographs Extension D - 0x2F800, 0x2FA1F, // CJK Compatibility Ideographs Supplement - 0xE0000, 0xE007F, // Tags - 0xE0100, 0xE01EF, // Variation Selectors Supplement - 0xF0000, 0xFFFFF, // Supplementary Private Use Area-A - 0x100000, 0x10FFFF, // Supplementary Private Use Area-B - 0xFFFFFFFF + 0x0000, 0x007F, // Basic Latin + 0x0080, 0x00FF, // Latin-1 Supplement + 0x0100, 0x017F, // Latin Extended-A + 0x0180, 0x024F, // Latin Extended-B + 0x0250, 0x02AF, // IPA Extensions + 0x02B0, 0x02FF, // Spacing Modifier Letters + 0x0300, 0x036F, // Combining Diacritical Marks + 0x0370, 0x03FF, // Greek and Coptic + 0x0400, 0x04FF, // Cyrillic + 0x0500, 0x052F, // Cyrillic Supplement + 0x0530, 0x058F, // Armenian + 0x0590, 0x05FF, // Hebrew + 0x0600, 0x06FF, // Arabic + 0x0700, 0x074F, // Syriac + 0x0750, 0x077F, // Arabic Supplement + 0x0780, 0x07BF, // Thaana + 0x07C0, 0x07FF, // NKo + 0x0800, 0x083F, // Samaritan + 0x0840, 0x085F, // Mandaic + 0x0900, 0x097F, // Devanagari + 0x0980, 0x09FF, // Bengali + 0x0A00, 0x0A7F, // Gurmukhi + 0x0A80, 0x0AFF, // Gujarati + 0x0B00, 0x0B7F, // Oriya + 0x0B80, 0x0BFF, // Tamil + 0x0C00, 0x0C7F, // Telugu + 0x0C80, 0x0CFF, // Kannada + 0x0D00, 0x0D7F, // Malayalam + 0x0D80, 0x0DFF, // Sinhala + 0x0E00, 0x0E7F, // Thai + 0x0E80, 0x0EFF, // Lao + 0x0F00, 0x0FFF, // Tibetan + 0x1000, 0x109F, // Myanmar + 0x10A0, 0x10FF, // Georgian + 0x1100, 0x11FF, // Hangul Jamo + 0x1200, 0x137F, // Ethiopic + 0x1380, 0x139F, // Ethiopic Supplement + 0x13A0, 0x13FF, // Cherokee + 0x1400, 0x167F, // Unified Canadian Aboriginal Syllabics + 0x1680, 0x169F, // Ogham + 0x16A0, 0x16FF, // Runic + 0x1700, 0x171F, // Tagalog + 0x1720, 0x173F, // Hanunoo + 0x1740, 0x175F, // Buhid + 0x1760, 0x177F, // Tagbanwa + 0x1780, 0x17FF, // Khmer + 0x1800, 0x18AF, // Mongolian + 0x18B0, 0x18FF, // Unified Canadian Aboriginal Syllabics Extended + 0x1900, 0x194F, // Limbu + 0x1950, 0x197F, // Tai Le + 0x1980, 0x19DF, // New Tai Lue + 0x19E0, 0x19FF, // Khmer Symbols + 0x1A00, 0x1A1F, // Buginese + 0x1A20, 0x1AAF, // Tai Tham + 0x1B00, 0x1B7F, // Balinese + 0x1B80, 0x1BBF, // Sundanese + 0x1BC0, 0x1BFF, // Batak + 0x1C00, 0x1C4F, // Lepcha + 0x1C50, 0x1C7F, // Ol Chiki + 0x1CD0, 0x1CFF, // Vedic Extensions + 0x1D00, 0x1D7F, // Phonetic Extensions + 0x1D80, 0x1DBF, // Phonetic Extensions Supplement + 0x1DC0, 0x1DFF, // Combining Diacritical Marks Supplement + 0x1E00, 0x1EFF, // Latin Extended Additional + 0x1F00, 0x1FFF, // Greek Extended + 0x2000, 0x206F, // General Punctuation + 0x2070, 0x209F, // Superscripts and Subscripts + 0x20A0, 0x20CF, // Currency Symbols + 0x20D0, 0x20FF, // Combining Diacritical Marks for Symbols + 0x2100, 0x214F, // Letterlike Symbols + 0x2150, 0x218F, // Number Forms + 0x2190, 0x21FF, // Arrows + 0x2200, 0x22FF, // Mathematical Operators + 0x2300, 0x23FF, // Miscellaneous Technical + 0x2400, 0x243F, // Control Pictures + 0x2440, 0x245F, // Optical Character Recognition + 0x2460, 0x24FF, // Enclosed Alphanumerics + 0x2500, 0x257F, // Box Drawing + 0x2580, 0x259F, // Block Elements + 0x25A0, 0x25FF, // Geometric Shapes + 0x2600, 0x26FF, // Miscellaneous Symbols + 0x2700, 0x27BF, // Dingbats + 0x27C0, 0x27EF, // Miscellaneous Mathematical Symbols-A + 0x27F0, 0x27FF, // Supplemental Arrows-A + 0x2800, 0x28FF, // Braille Patterns + 0x2900, 0x297F, // Supplemental Arrows-B + 0x2980, 0x29FF, // Miscellaneous Mathematical Symbols-B + 0x2A00, 0x2AFF, // Supplemental Mathematical Operators + 0x2B00, 0x2BFF, // Miscellaneous Symbols and Arrows + 0x2C00, 0x2C5F, // Glagolitic + 0x2C60, 0x2C7F, // Latin Extended-C + 0x2C80, 0x2CFF, // Coptic + 0x2D00, 0x2D2F, // Georgian Supplement + 0x2D30, 0x2D7F, // Tifinagh + 0x2D80, 0x2DDF, // Ethiopic Extended + 0x2DE0, 0x2DFF, // Cyrillic Extended-A + 0x2E00, 0x2E7F, // Supplemental Punctuation + 0x2E80, 0x2EFF, // CJK Radicals Supplement + 0x2F00, 0x2FDF, // Kangxi Radicals + 0x2FF0, 0x2FFF, // Ideographic Description Characters + 0x3000, 0x303F, // CJK Symbols and Punctuation + 0x3040, 0x309F, // Hiragana + 0x30A0, 0x30FF, // Katakana + 0x3100, 0x312F, // Bopomofo + 0x3130, 0x318F, // Hangul Compatibility Jamo + 0x3190, 0x319F, // Kanbun + 0x31A0, 0x31BF, // Bopomofo Extended + 0x31C0, 0x31EF, // CJK Strokes + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0x3200, 0x32FF, // Enclosed CJK Letters and Months + 0x3300, 0x33FF, // CJK Compatibility + 0x3400, 0x4DBF, // CJK Unified Ideographs Extension A + 0x4DC0, 0x4DFF, // Yijing Hexagram Symbols + 0x4E00, 0x9FFF, // CJK Unified Ideographs + 0xA000, 0xA48F, // Yi Syllables + 0xA490, 0xA4CF, // Yi Radicals + 0xA4D0, 0xA4FF, // Lisu + 0xA500, 0xA63F, // Vai + 0xA640, 0xA69F, // Cyrillic Extended-B + 0xA6A0, 0xA6FF, // Bamum + 0xA700, 0xA71F, // Modifier Tone Letters + 0xA720, 0xA7FF, // Latin Extended-D + 0xA800, 0xA82F, // Syloti Nagri + 0xA830, 0xA83F, // Common Indic Number Forms + 0xA840, 0xA87F, // Phags-pa + 0xA880, 0xA8DF, // Saurashtra + 0xA8E0, 0xA8FF, // Devanagari Extended + 0xA900, 0xA92F, // Kayah Li + 0xA930, 0xA95F, // Rejang + 0xA960, 0xA97F, // Hangul Jamo Extended-A + 0xA980, 0xA9DF, // Javanese + 0xAA00, 0xAA5F, // Cham + 0xAA60, 0xAA7F, // Myanmar Extended-A + 0xAA80, 0xAADF, // Tai Viet + 0xAB00, 0xAB2F, // Ethiopic Extended-A + 0xABC0, 0xABFF, // Meetei Mayek + 0xAC00, 0xD7AF, // Hangul Syllables + 0xD7B0, 0xD7FF, // Hangul Jamo Extended-B + //0xD800, 0xDB7F, // High Surrogates + //0xDB80, 0xDBFF, // High Private Use Surrogates + //0xDC00, 0xDFFF, // Low Surrogates + 0xE000, 0xF8FF, // Private Use Area + 0xF900, 0xFAFF, // CJK Compatibility Ideographs + 0xFB00, 0xFB4F, // Alphabetic Presentation Forms + 0xFB50, 0xFDFF, // Arabic Presentation Forms-A + 0xFE00, 0xFE0F, // Variation Selectors + 0xFE10, 0xFE1F, // Vertical Forms + 0xFE20, 0xFE2F, // Combining Half Marks + 0xFE30, 0xFE4F, // CJK Compatibility Forms + 0xFE50, 0xFE6F, // Small Form Variants + 0xFE70, 0xFEFF, // Arabic Presentation Forms-B + 0xFF00, 0xFFEF, // Halfwidth and Fullwidth Forms + 0xFFF0, 0xFFFF, // Specials + 0x10000, 0x1007F, // Linear B Syllabary + 0x10080, 0x100FF, // Linear B Ideograms + 0x10100, 0x1013F, // Aegean Numbers + 0x10140, 0x1018F, // Ancient Greek Numbers + 0x10190, 0x101CF, // Ancient Symbols + 0x101D0, 0x101FF, // Phaistos Disc + 0x10280, 0x1029F, // Lycian + 0x102A0, 0x102DF, // Carian + 0x10300, 0x1032F, // Old Italic + 0x10330, 0x1034F, // Gothic + 0x10380, 0x1039F, // Ugaritic + 0x103A0, 0x103DF, // Old Persian + 0x10400, 0x1044F, // Deseret + 0x10450, 0x1047F, // Shavian + 0x10480, 0x104AF, // Osmanya + 0x10800, 0x1083F, // Cypriot Syllabary + 0x10840, 0x1085F, // Imperial Aramaic + 0x10900, 0x1091F, // Phoenician + 0x10920, 0x1093F, // Lydian + 0x10A00, 0x10A5F, // Kharoshthi + 0x10A60, 0x10A7F, // Old South Arabian + 0x10B00, 0x10B3F, // Avestan + 0x10B40, 0x10B5F, // Inscriptional Parthian + 0x10B60, 0x10B7F, // Inscriptional Pahlavi + 0x10C00, 0x10C4F, // Old Turkic + 0x10E60, 0x10E7F, // Rumi Numeral Symbols + 0x11000, 0x1107F, // Brahmi + 0x11080, 0x110CF, // Kaithi + 0x12000, 0x123FF, // Cuneiform + 0x12400, 0x1247F, // Cuneiform Numbers and Punctuation + 0x13000, 0x1342F, // Egyptian Hieroglyphs + 0x16800, 0x16A3F, // Bamum Supplement + 0x1B000, 0x1B0FF, // Kana Supplement + 0x1D000, 0x1D0FF, // Byzantine Musical Symbols + 0x1D100, 0x1D1FF, // Musical Symbols + 0x1D200, 0x1D24F, // Ancient Greek Musical Notation + 0x1D300, 0x1D35F, // Tai Xuan Jing Symbols + 0x1D360, 0x1D37F, // Counting Rod Numerals + 0x1D400, 0x1D7FF, // Mathematical Alphanumeric Symbols + 0x1F000, 0x1F02F, // Mahjong Tiles + 0x1F030, 0x1F09F, // Domino Tiles + 0x1F0A0, 0x1F0FF, // Playing Cards + 0x1F100, 0x1F1FF, // Enclosed Alphanumeric Supplement + 0x1F200, 0x1F2FF, // Enclosed Ideographic Supplement + 0x1F300, 0x1F5FF, // Miscellaneous Symbols And Pictographs + 0x1F600, 0x1F64F, // Emoticons + 0x1F680, 0x1F6FF, // Transport And Map Symbols + 0x1F700, 0x1F77F, // Alchemical Symbols + 0x20000, 0x2A6DF, // CJK Unified Ideographs Extension B + 0x2A700, 0x2B73F, // CJK Unified Ideographs Extension C + 0x2B740, 0x2B81F, // CJK Unified Ideographs Extension D + 0x2F800, 0x2FA1F, // CJK Compatibility Ideographs Supplement + 0xE0000, 0xE007F, // Tags + 0xE0100, 0xE01EF, // Variation Selectors Supplement + 0xF0000, 0xFFFFF, // Supplementary Private Use Area-A + 0x100000, 0x10FFFF, // Supplementary Private Use Area-B + 0xFFFFFFFF }; // Copyright (c) 2008-2010 Bjoern Hoehrmann @@ -229,184 +249,184 @@ static const unsigned kCodepointRanges[] = { #define UTF8_REJECT 12u static const unsigned char utf8d[] = { - // The first part of the table maps bytes to character classes that - // to reduce the size of the transition table and create bitmasks. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, + // The first part of the table maps bytes to character classes that + // to reduce the size of the transition table and create bitmasks. + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, - // The second part is a transition table that maps a combination - // of a state of the automaton and a character class to a state. - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, - 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, - 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, - 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, - 12,36,12,12,12,12,12,12,12,12,12,12, + // The second part is a transition table that maps a combination + // of a state of the automaton and a character class to a state. + 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, + 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, + 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, + 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, + 12,36,12,12,12,12,12,12,12,12,12,12, }; static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) { - unsigned type = utf8d[byte]; + unsigned type = utf8d[byte]; - *codep = (*state != UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); + *codep = (*state != UTF8_ACCEPT) ? + (byte & 0x3fu) | (*codep << 6) : + (0xff >> type) & (byte); - *state = utf8d[256 + *state + type]; - return *state; + *state = utf8d[256 + *state + type]; + return *state; } //static bool IsUTF8(unsigned char* s) { -// unsigned codepoint, state = 0; +// unsigned codepoint, state = 0; // -// while (*s) -// decode(&state, &codepoint, *s++); +// while (*s) +// decode(&state, &codepoint, *s++); // -// return state == UTF8_ACCEPT; +// return state == UTF8_ACCEPT; //} TEST(EncodingsTest, UTF8) { - StringBuffer os, os2; - for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) { - for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) { - os.Clear(); - UTF8<>::Encode(os, codepoint); - const char* encodedStr = os.GetString(); + StringBuffer os, os2; + for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) { + for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) { + os.Clear(); + UTF8<>::Encode(os, codepoint); + const char* encodedStr = os.GetString(); - // Decode with Hoehrmann - { - unsigned decodedCodepoint = 0; - unsigned state = 0; + // Decode with Hoehrmann + { + unsigned decodedCodepoint = 0; + unsigned state = 0; - unsigned decodedCount = 0; - for (const char* s = encodedStr; *s; ++s) - if (!decode(&state, &decodedCodepoint, (unsigned char)*s)) { - EXPECT_EQ(codepoint, decodedCodepoint); - decodedCount++; - } + unsigned decodedCount = 0; + for (const char* s = encodedStr; *s; ++s) + if (!decode(&state, &decodedCodepoint, (unsigned char)*s)) { + EXPECT_EQ(codepoint, decodedCodepoint); + decodedCount++; + } - if (*encodedStr) // This decoder cannot handle U+0000 - EXPECT_EQ(1u, decodedCount); // Should only contain one code point + if (*encodedStr) // This decoder cannot handle U+0000 + EXPECT_EQ(1u, decodedCount); // Should only contain one code point - EXPECT_EQ(UTF8_ACCEPT, state); - if (UTF8_ACCEPT != state) - std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; - } + EXPECT_EQ(UTF8_ACCEPT, state); + if (UTF8_ACCEPT != state) + std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; + } - // Decode - { - StringStream is(encodedStr); - unsigned decodedCodepoint; - bool result = UTF8<>::Decode(is, &decodedCodepoint); - EXPECT_TRUE(result); - EXPECT_EQ(codepoint, decodedCodepoint); - if (!result || codepoint != decodedCodepoint) - std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; - } + // Decode + { + StringStream is(encodedStr); + unsigned decodedCodepoint; + bool result = UTF8<>::Decode(is, &decodedCodepoint); + EXPECT_TRUE(result); + EXPECT_EQ(codepoint, decodedCodepoint); + if (!result || codepoint != decodedCodepoint) + std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; + } - // Validate - { - StringStream is(encodedStr); - os2.Clear(); - bool result = UTF8<>::Validate(is, os2); - EXPECT_TRUE(result); - EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString())); - } - } - } + // Validate + { + StringStream is(encodedStr); + os2.Clear(); + bool result = UTF8<>::Validate(is, os2); + EXPECT_TRUE(result); + EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString())); + } + } + } } TEST(EncodingsTest, UTF16) { - GenericStringBuffer > os, os2; - GenericStringBuffer > utf8os; - for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) { - for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) { - os.Clear(); - UTF16<>::Encode(os, codepoint); - const UTF16<>::Ch* encodedStr = os.GetString(); + GenericStringBuffer > os, os2; + GenericStringBuffer > utf8os; + for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) { + for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) { + os.Clear(); + UTF16<>::Encode(os, codepoint); + const UTF16<>::Ch* encodedStr = os.GetString(); - // Encode with Hoehrmann's code - if (codepoint != 0) // cannot handle U+0000 - { - // encode with UTF8<> first - utf8os.Clear(); - UTF8<>::Encode(utf8os, codepoint); + // Encode with Hoehrmann's code + if (codepoint != 0) // cannot handle U+0000 + { + // encode with UTF8<> first + utf8os.Clear(); + UTF8<>::Encode(utf8os, codepoint); - // transcode from UTF8 to UTF16 with Hoehrmann's code - unsigned decodedCodepoint = 0; - unsigned state = 0; - UTF16<>::Ch buffer[3], *p = &buffer[0]; - for (const char* s = utf8os.GetString(); *s; ++s) { - if (!decode(&state, &decodedCodepoint, (unsigned char)*s)) - break; - } + // transcode from UTF8 to UTF16 with Hoehrmann's code + unsigned decodedCodepoint = 0; + unsigned state = 0; + UTF16<>::Ch buffer[3], *p = &buffer[0]; + for (const char* s = utf8os.GetString(); *s; ++s) { + if (!decode(&state, &decodedCodepoint, (unsigned char)*s)) + break; + } - if (codepoint <= 0xFFFF) - *p++ = static_cast::Ch>(decodedCodepoint); - else { - // Encode code points above U+FFFF as surrogate pair. - *p++ = static_cast::Ch>(0xD7C0 + (decodedCodepoint >> 10)); - *p++ = static_cast::Ch>(0xDC00 + (decodedCodepoint & 0x3FF)); - } - *p++ = '\0'; + if (codepoint <= 0xFFFF) + *p++ = static_cast::Ch>(decodedCodepoint); + else { + // Encode code points above U+FFFF as surrogate pair. + *p++ = static_cast::Ch>(0xD7C0 + (decodedCodepoint >> 10)); + *p++ = static_cast::Ch>(0xDC00 + (decodedCodepoint & 0x3FF)); + } + *p++ = '\0'; - EXPECT_EQ(0, StrCmp(buffer, encodedStr)); - } + EXPECT_EQ(0, StrCmp(buffer, encodedStr)); + } - // Decode - { - GenericStringStream > is(encodedStr); - unsigned decodedCodepoint; - bool result = UTF16<>::Decode(is, &decodedCodepoint); - EXPECT_TRUE(result); - EXPECT_EQ(codepoint, decodedCodepoint); - if (!result || codepoint != decodedCodepoint) - std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; - } + // Decode + { + GenericStringStream > is(encodedStr); + unsigned decodedCodepoint; + bool result = UTF16<>::Decode(is, &decodedCodepoint); + EXPECT_TRUE(result); + EXPECT_EQ(codepoint, decodedCodepoint); + if (!result || codepoint != decodedCodepoint) + std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; + } - // Validate - { - GenericStringStream > is(encodedStr); - os2.Clear(); - bool result = UTF16<>::Validate(is, os2); - EXPECT_TRUE(result); - EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString())); - } - } - } + // Validate + { + GenericStringStream > is(encodedStr); + os2.Clear(); + bool result = UTF16<>::Validate(is, os2); + EXPECT_TRUE(result); + EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString())); + } + } + } } TEST(EncodingsTest, UTF32) { - GenericStringBuffer > os, os2; - for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) { - for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) { - os.Clear(); - UTF32<>::Encode(os, codepoint); - const UTF32<>::Ch* encodedStr = os.GetString(); + GenericStringBuffer > os, os2; + for (const unsigned* range = kCodepointRanges; *range != 0xFFFFFFFF; range += 2) { + for (unsigned codepoint = range[0]; codepoint <= range[1]; ++codepoint) { + os.Clear(); + UTF32<>::Encode(os, codepoint); + const UTF32<>::Ch* encodedStr = os.GetString(); - // Decode - { - GenericStringStream > is(encodedStr); - unsigned decodedCodepoint; - bool result = UTF32<>::Decode(is, &decodedCodepoint); - EXPECT_TRUE(result); - EXPECT_EQ(codepoint, decodedCodepoint); - if (!result || codepoint != decodedCodepoint) - std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; - } + // Decode + { + GenericStringStream > is(encodedStr); + unsigned decodedCodepoint; + bool result = UTF32<>::Decode(is, &decodedCodepoint); + EXPECT_TRUE(result); + EXPECT_EQ(codepoint, decodedCodepoint); + if (!result || codepoint != decodedCodepoint) + std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl; + } - // Validate - { - GenericStringStream > is(encodedStr); - os2.Clear(); - bool result = UTF32<>::Validate(is, os2); - EXPECT_TRUE(result); - EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString())); - } - } - } + // Validate + { + GenericStringStream > is(encodedStr); + os2.Clear(); + bool result = UTF32<>::Validate(is, os2); + EXPECT_TRUE(result); + EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString())); + } + } + } } diff --git a/test/unittest/filestreamtest.cpp b/test/unittest/filestreamtest.cpp index 20a8438..c3217fa 100644 --- a/test/unittest/filestreamtest.cpp +++ b/test/unittest/filestreamtest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" #include "rapidjson/filestream.h" #include "rapidjson/filereadstream.h" @@ -8,96 +28,96 @@ using namespace rapidjson; class FileStreamTest : public ::testing::Test { public: - FileStreamTest() : filename_(), json_(), length_() {} + FileStreamTest() : filename_(), json_(), length_() {} - virtual void SetUp() { - FILE *fp = fopen(filename_ = "data/sample.json", "rb"); - if (!fp) - fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); - ASSERT_TRUE(fp != 0); + virtual void SetUp() { + FILE *fp = fopen(filename_ = "data/sample.json", "rb"); + if (!fp) + fp = fopen(filename_ = "../../bin/data/sample.json", "rb"); + ASSERT_TRUE(fp != 0); - fseek(fp, 0, SEEK_END); - length_ = (size_t)ftell(fp); - fseek(fp, 0, SEEK_SET); - json_ = (char*)malloc(length_ + 1); - size_t readLength = fread(json_, 1, length_, fp); - json_[readLength] = '\0'; - fclose(fp); - } + fseek(fp, 0, SEEK_END); + length_ = (size_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + json_ = (char*)malloc(length_ + 1); + size_t readLength = fread(json_, 1, length_, fp); + json_[readLength] = '\0'; + fclose(fp); + } - virtual void TearDown() { - free(json_); - json_ = 0; - } + virtual void TearDown() { + free(json_); + json_ = 0; + } private: - FileStreamTest(const FileStreamTest&); - FileStreamTest& operator=(const FileStreamTest&); - + FileStreamTest(const FileStreamTest&); + FileStreamTest& operator=(const FileStreamTest&); + protected: - const char* filename_; - char *json_; - size_t length_; + const char* filename_; + char *json_; + size_t length_; }; // Depreciated //TEST_F(FileStreamTest, FileStream_Read) { -// FILE *fp = fopen(filename_, "rb"); -// ASSERT_TRUE(fp != 0); -// FileStream s(fp); +// FILE *fp = fopen(filename_, "rb"); +// ASSERT_TRUE(fp != 0); +// FileStream s(fp); // -// for (size_t i = 0; i < length_; i++) { -// EXPECT_EQ(json_[i], s.Peek()); -// EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same -// EXPECT_EQ(json_[i], s.Take()); -// } +// for (size_t i = 0; i < length_; i++) { +// EXPECT_EQ(json_[i], s.Peek()); +// EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same +// EXPECT_EQ(json_[i], s.Take()); +// } // -// EXPECT_EQ(length_, s.Tell()); -// EXPECT_EQ('\0', s.Peek()); +// EXPECT_EQ(length_, s.Tell()); +// EXPECT_EQ('\0', s.Peek()); // -// fclose(fp); +// fclose(fp); //} TEST_F(FileStreamTest, FileReadStream) { - FILE *fp = fopen(filename_, "rb"); - ASSERT_TRUE(fp != 0); - char buffer[65536]; - FileReadStream s(fp, buffer, sizeof(buffer)); + FILE *fp = fopen(filename_, "rb"); + ASSERT_TRUE(fp != 0); + char buffer[65536]; + FileReadStream s(fp, buffer, sizeof(buffer)); - for (size_t i = 0; i < length_; i++) { - EXPECT_EQ(json_[i], s.Peek()); - EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same - EXPECT_EQ(json_[i], s.Take()); - } + for (size_t i = 0; i < length_; i++) { + EXPECT_EQ(json_[i], s.Peek()); + EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same + EXPECT_EQ(json_[i], s.Take()); + } - EXPECT_EQ(length_, s.Tell()); - EXPECT_EQ('\0', s.Peek()); + EXPECT_EQ(length_, s.Tell()); + EXPECT_EQ('\0', s.Peek()); - fclose(fp); + fclose(fp); } TEST_F(FileStreamTest, FileWriteStream) { - char filename[L_tmpnam]; - TempFilename(filename); + char filename[L_tmpnam]; + TempFilename(filename); - FILE *fp = fopen(filename, "wb"); - char buffer[65536]; - FileWriteStream os(fp, buffer, sizeof(buffer)); - for (size_t i = 0; i < length_; i++) - os.Put(json_[i]); - os.Flush(); - fclose(fp); + FILE *fp = fopen(filename, "wb"); + char buffer[65536]; + FileWriteStream os(fp, buffer, sizeof(buffer)); + for (size_t i = 0; i < length_; i++) + os.Put(json_[i]); + os.Flush(); + fclose(fp); - // Read it back to verify - fp = fopen(filename, "rb"); - FileReadStream is(fp, buffer, sizeof(buffer)); + // Read it back to verify + fp = fopen(filename, "rb"); + FileReadStream is(fp, buffer, sizeof(buffer)); - for (size_t i = 0; i < length_; i++) - EXPECT_EQ(json_[i], is.Take()); + for (size_t i = 0; i < length_; i++) + EXPECT_EQ(json_[i], is.Take()); - EXPECT_EQ(length_, is.Tell()); - fclose(fp); + EXPECT_EQ(length_, is.Tell()); + fclose(fp); - //std::cout << filename << std::endl; - remove(filename); + //std::cout << filename << std::endl; + remove(filename); } diff --git a/test/unittest/jsoncheckertest.cpp b/test/unittest/jsoncheckertest.cpp index 91e6262..d661528 100644 --- a/test/unittest/jsoncheckertest.cpp +++ b/test/unittest/jsoncheckertest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" #include "rapidjson/document.h" @@ -5,66 +25,66 @@ using namespace rapidjson; static char* ReadFile(const char* filename, size_t& length) { - FILE *fp = fopen(filename, "rb"); - if (!fp) - fp = fopen(filename, "rb"); - if (!fp) - return 0; + FILE *fp = fopen(filename, "rb"); + if (!fp) + fp = fopen(filename, "rb"); + if (!fp) + return 0; - fseek(fp, 0, SEEK_END); - length = (size_t)ftell(fp); - fseek(fp, 0, SEEK_SET); - char* json = (char*)malloc(length + 1); - size_t readLength = fread(json, 1, length, fp); - json[readLength] = '\0'; - fclose(fp); - return json; + fseek(fp, 0, SEEK_END); + length = (size_t)ftell(fp); + fseek(fp, 0, SEEK_SET); + char* json = (char*)malloc(length + 1); + size_t readLength = fread(json, 1, length, fp); + json[readLength] = '\0'; + fclose(fp); + return json; } TEST(JsonChecker, Reader) { - char filename[256]; + char filename[256]; - // jsonchecker/failXX.json - for (int i = 1; i <= 33; i++) { - if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting. - continue; + // jsonchecker/failXX.json + for (int i = 1; i <= 33; i++) { + if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting. + continue; - sprintf(filename, "jsonchecker/fail%d.json", i); - size_t length; - char* json = ReadFile(filename, length); - if (!json) { - sprintf(filename, "../../bin/jsonchecker/fail%d.json", i); - json = ReadFile(filename, length); - if (!json) { - printf("jsonchecker file %s not found", filename); - continue; - } - } + sprintf(filename, "jsonchecker/fail%d.json", i); + size_t length; + char* json = ReadFile(filename, length); + if (!json) { + sprintf(filename, "../../bin/jsonchecker/fail%d.json", i); + json = ReadFile(filename, length); + if (!json) { + printf("jsonchecker file %s not found", filename); + continue; + } + } - GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) - if (!document.Parse((const char*)json).HasParseError()) - FAIL(); - //printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError()); - free(json); - } + GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) + if (!document.Parse((const char*)json).HasParseError()) + FAIL(); + //printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError()); + free(json); + } - // passX.json - for (int i = 1; i <= 3; i++) { - sprintf(filename, "jsonchecker/pass%d.json", i); - size_t length; - char* json = ReadFile(filename, length); - if (!json) { - sprintf(filename, "../../bin/jsonchecker/pass%d.json", i); - json = ReadFile(filename, length); - if (!json) { - printf("jsonchecker file %s not found", filename); - continue; - } - } + // passX.json + for (int i = 1; i <= 3; i++) { + sprintf(filename, "jsonchecker/pass%d.json", i); + size_t length; + char* json = ReadFile(filename, length); + if (!json) { + sprintf(filename, "../../bin/jsonchecker/pass%d.json", i); + json = ReadFile(filename, length); + if (!json) { + printf("jsonchecker file %s not found", filename); + continue; + } + } - GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) - document.Parse((const char*)json); - EXPECT_TRUE(!document.HasParseError()); - free(json); - } + GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) + document.Parse((const char*)json); + EXPECT_TRUE(!document.HasParseError()); + free(json); + } } diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index afe0cd7..e403bb8 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1,6 +1,26 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" -#define private public // For testing private members +#define private public // For testing private members #include "rapidjson/reader.h" using namespace rapidjson; @@ -12,399 +32,399 @@ RAPIDJSON_DIAG_OFF(effc++) template struct ParseBoolHandler : BaseReaderHandler<> { - ParseBoolHandler() : step_(0) {} - bool Default() { ADD_FAILURE(); return false; } - // gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version. - // Workaround with EXPECT_TRUE(). - bool Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++step_; return true; } + ParseBoolHandler() : step_(0) {} + bool Default() { ADD_FAILURE(); return false; } + // gcc 4.8.x generates warning in EXPECT_EQ(bool, bool) on this gtest version. + // Workaround with EXPECT_TRUE(). + bool Bool(bool b) { /*EXPECT_EQ(expect, b); */EXPECT_TRUE(expect == b); ++step_; return true; } - unsigned step_; + unsigned step_; }; TEST(Reader, ParseTrue) { - StringStream s("true"); - ParseBoolHandler h; - Reader reader; - reader.ParseTrue<0>(s, h); - EXPECT_EQ(1u, h.step_); + StringStream s("true"); + ParseBoolHandler h; + Reader reader; + reader.ParseTrue<0>(s, h); + EXPECT_EQ(1u, h.step_); } TEST(Reader, ParseFalse) { - StringStream s("false"); - ParseBoolHandler h; - Reader reader; - reader.ParseFalse<0>(s, h); - EXPECT_EQ(1u, h.step_); + StringStream s("false"); + ParseBoolHandler h; + Reader reader; + reader.ParseFalse<0>(s, h); + EXPECT_EQ(1u, h.step_); } struct ParseIntHandler : BaseReaderHandler<> { - ParseIntHandler() : step_(0), actual_() {} - bool Default() { ADD_FAILURE(); return false; } - bool Int(int i) { actual_ = i; step_++; return true; } + ParseIntHandler() : step_(0), actual_() {} + bool Default() { ADD_FAILURE(); return false; } + bool Int(int i) { actual_ = i; step_++; return true; } - unsigned step_; - int actual_; + unsigned step_; + int actual_; }; struct ParseUintHandler : BaseReaderHandler<> { - ParseUintHandler() : step_(0), actual_() {} - bool Default() { ADD_FAILURE(); return false; } - bool Uint(unsigned i) { actual_ = i; step_++; return true; } + ParseUintHandler() : step_(0), actual_() {} + bool Default() { ADD_FAILURE(); return false; } + bool Uint(unsigned i) { actual_ = i; step_++; return true; } - unsigned step_; - unsigned actual_; + unsigned step_; + unsigned actual_; }; struct ParseInt64Handler : BaseReaderHandler<> { - ParseInt64Handler() : step_(0), actual_() {} - bool Default() { ADD_FAILURE(); return false; } - bool Int64(int64_t i) { actual_ = i; step_++; return true; } + ParseInt64Handler() : step_(0), actual_() {} + bool Default() { ADD_FAILURE(); return false; } + bool Int64(int64_t i) { actual_ = i; step_++; return true; } - unsigned step_; - int64_t actual_; + unsigned step_; + int64_t actual_; }; struct ParseUint64Handler : BaseReaderHandler<> { - ParseUint64Handler() : step_(0), actual_() {} - bool Default() { ADD_FAILURE(); return false; } - bool Uint64(uint64_t i) { actual_ = i; step_++; return true; } + ParseUint64Handler() : step_(0), actual_() {} + bool Default() { ADD_FAILURE(); return false; } + bool Uint64(uint64_t i) { actual_ = i; step_++; return true; } - unsigned step_; - uint64_t actual_; + unsigned step_; + uint64_t actual_; }; struct ParseDoubleHandler : BaseReaderHandler<> { - ParseDoubleHandler() : step_(0), actual_() {} - bool Default() { ADD_FAILURE(); return false; } - bool Double(double d) { actual_ = d; step_++; return true; } + ParseDoubleHandler() : step_(0), actual_() {} + bool Default() { ADD_FAILURE(); return false; } + bool Double(double d) { actual_ = d; step_++; return true; } - unsigned step_; - double actual_; + unsigned step_; + double actual_; }; TEST(Reader, ParseNumberHandler) { #define TEST_NUMBER(Handler, str, x) \ - { \ - StringStream s(str); \ - Handler h; \ - Reader reader; \ - reader.ParseNumber<0>(s, h); \ - EXPECT_EQ(1u, h.step_); \ - EXPECT_EQ(double(x), h.actual_); \ - } + { \ + StringStream s(str); \ + Handler h; \ + Reader reader; \ + reader.ParseNumber<0>(s, h); \ + EXPECT_EQ(1u, h.step_); \ + EXPECT_EQ(double(x), h.actual_); \ + } #define TEST_DOUBLE(str, x) \ - { \ - StringStream s(str); \ - ParseDoubleHandler h; \ - Reader reader; \ - reader.ParseNumber<0>(s, h); \ - EXPECT_EQ(1u, h.step_); \ - EXPECT_DOUBLE_EQ(x, h.actual_); \ - } + { \ + StringStream s(str); \ + ParseDoubleHandler h; \ + Reader reader; \ + reader.ParseNumber<0>(s, h); \ + EXPECT_EQ(1u, h.step_); \ + EXPECT_DOUBLE_EQ(x, h.actual_); \ + } - TEST_NUMBER(ParseUintHandler, "0", 0); - TEST_NUMBER(ParseUintHandler, "123", 123); - TEST_NUMBER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int) - TEST_NUMBER(ParseUintHandler, "4294967295", 4294967295u); + TEST_NUMBER(ParseUintHandler, "0", 0); + TEST_NUMBER(ParseUintHandler, "123", 123); + TEST_NUMBER(ParseUintHandler, "2147483648", 2147483648u); // 2^31 - 1 (cannot be stored in int) + TEST_NUMBER(ParseUintHandler, "4294967295", 4294967295u); - TEST_NUMBER(ParseIntHandler, "-123", -123); - TEST_NUMBER(ParseIntHandler, "-2147483648", -2147483648LL); // -2^31 (min of int) + TEST_NUMBER(ParseIntHandler, "-123", -123); + TEST_NUMBER(ParseIntHandler, "-2147483648", -2147483648LL); // -2^31 (min of int) - TEST_NUMBER(ParseUint64Handler, "4294967296", 4294967296ULL); // 2^32 (max of unsigned + 1, force to use uint64_t) - TEST_NUMBER(ParseUint64Handler, "18446744073709551615", 18446744073709551615ULL); // 2^64 - 1 (max of uint64_t) + TEST_NUMBER(ParseUint64Handler, "4294967296", 4294967296ULL); // 2^32 (max of unsigned + 1, force to use uint64_t) + TEST_NUMBER(ParseUint64Handler, "18446744073709551615", 18446744073709551615ULL); // 2^64 - 1 (max of uint64_t) - TEST_NUMBER(ParseInt64Handler, "-2147483649", -2147483649LL); // -2^31 -1 (min of int - 1, force to use int64_t) - TEST_NUMBER(ParseInt64Handler, "-9223372036854775808", (-9223372036854775807LL - 1)); // -2^63 (min of int64_t) + TEST_NUMBER(ParseInt64Handler, "-2147483649", -2147483649LL); // -2^31 -1 (min of int - 1, force to use int64_t) + TEST_NUMBER(ParseInt64Handler, "-9223372036854775808", (-9223372036854775807LL - 1)); // -2^63 (min of int64_t) - TEST_DOUBLE("0.0", 0.0); - TEST_DOUBLE("1.0", 1.0); - TEST_DOUBLE("-1.0", -1.0); - TEST_DOUBLE("1.5", 1.5); - TEST_DOUBLE("-1.5", -1.5); - TEST_DOUBLE("3.1416", 3.1416); - TEST_DOUBLE("1E10", 1E10); - TEST_DOUBLE("1e10", 1e10); - TEST_DOUBLE("1E+10", 1E+10); - TEST_DOUBLE("1E-10", 1E-10); - TEST_DOUBLE("-1E10", -1E10); - TEST_DOUBLE("-1e10", -1e10); - TEST_DOUBLE("-1E+10", -1E+10); - TEST_DOUBLE("-1E-10", -1E-10); - TEST_DOUBLE("1.234E+10", 1.234E+10); - TEST_DOUBLE("1.234E-10", 1.234E-10); - TEST_DOUBLE("1.79769e+308", 1.79769e+308); - TEST_DOUBLE("2.22507e-308", 2.22507e-308); - TEST_DOUBLE("-1.79769e+308", -1.79769e+308); - TEST_DOUBLE("-2.22507e-308", -2.22507e-308); - TEST_DOUBLE("4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal - TEST_DOUBLE("1e-10000", 0.0); // must underflow - TEST_DOUBLE("18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) - TEST_DOUBLE("-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) + TEST_DOUBLE("0.0", 0.0); + TEST_DOUBLE("1.0", 1.0); + TEST_DOUBLE("-1.0", -1.0); + TEST_DOUBLE("1.5", 1.5); + TEST_DOUBLE("-1.5", -1.5); + TEST_DOUBLE("3.1416", 3.1416); + TEST_DOUBLE("1E10", 1E10); + TEST_DOUBLE("1e10", 1e10); + TEST_DOUBLE("1E+10", 1E+10); + TEST_DOUBLE("1E-10", 1E-10); + TEST_DOUBLE("-1E10", -1E10); + TEST_DOUBLE("-1e10", -1e10); + TEST_DOUBLE("-1E+10", -1E+10); + TEST_DOUBLE("-1E-10", -1E-10); + TEST_DOUBLE("1.234E+10", 1.234E+10); + TEST_DOUBLE("1.234E-10", 1.234E-10); + TEST_DOUBLE("1.79769e+308", 1.79769e+308); + TEST_DOUBLE("2.22507e-308", 2.22507e-308); + TEST_DOUBLE("-1.79769e+308", -1.79769e+308); + TEST_DOUBLE("-2.22507e-308", -2.22507e-308); + TEST_DOUBLE("4.9406564584124654e-324", 4.9406564584124654e-324); // minimum denormal + TEST_DOUBLE("1e-10000", 0.0); // must underflow + TEST_DOUBLE("18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) + TEST_DOUBLE("-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) - { - char n1e308[310]; // '1' followed by 308 '0' - n1e308[0] = '1'; - for (int i = 1; i < 309; i++) - n1e308[i] = '0'; - n1e308[309] = '\0'; - TEST_DOUBLE(n1e308, 1E308); - } + { + char n1e308[310]; // '1' followed by 308 '0' + n1e308[0] = '1'; + for (int i = 1; i < 309; i++) + n1e308[i] = '0'; + n1e308[309] = '\0'; + TEST_DOUBLE(n1e308, 1E308); + } #undef TEST_NUMBER #undef TEST_DOUBLE } TEST(Reader, ParseNumber_Error) { #define TEST_NUMBER_ERROR(errorCode, str) \ - { \ - char buffer[1001]; \ - sprintf(buffer, "[%s]", str); \ - InsituStringStream s(buffer); \ - BaseReaderHandler<> h; \ - Reader reader; \ - EXPECT_FALSE(reader.Parse<0>(s, h)); \ - EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ - } + { \ + char buffer[1001]; \ + sprintf(buffer, "[%s]", str); \ + InsituStringStream s(buffer); \ + BaseReaderHandler<> h; \ + Reader reader; \ + EXPECT_FALSE(reader.Parse<0>(s, h)); \ + EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ + } - // Number too big to be stored in double. - { - char n1e309[311]; // '1' followed by 309 '0' - n1e309[0] = '1'; - for (int i = 1; i < 310; i++) - n1e309[i] = '0'; - n1e309[310] = '\0'; - TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309); - } - TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309"); + // Number too big to be stored in double. + { + char n1e309[311]; // '1' followed by 309 '0' + n1e309[0] = '1'; + for (int i = 1; i < 310; i++) + n1e309[i] = '0'; + n1e309[310] = '\0'; + TEST_NUMBER_ERROR(kParseErrorNumberTooBig, n1e309); + } + TEST_NUMBER_ERROR(kParseErrorNumberTooBig, "1e309"); - // Miss fraction part in number. - TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1."); - TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a"); + // Miss fraction part in number. + TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1."); + TEST_NUMBER_ERROR(kParseErrorNumberMissFraction, "1.a"); - // Miss exponent in number. - TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e"); - TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_"); + // Miss exponent in number. + TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e"); + TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_"); #undef TEST_NUMBER_ERROR } template struct ParseStringHandler : BaseReaderHandler { - ParseStringHandler() : str_(0), length_(0), copy_() {} - ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast(str_)); } - - ParseStringHandler(const ParseStringHandler&); - ParseStringHandler& operator=(const ParseStringHandler&); + ParseStringHandler() : str_(0), length_(0), copy_() {} + ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast(str_)); } + + ParseStringHandler(const ParseStringHandler&); + ParseStringHandler& operator=(const ParseStringHandler&); - bool Default() { ADD_FAILURE(); return false; } - bool String(const typename Encoding::Ch* str, size_t length, bool copy) { - EXPECT_EQ(0, str_); - if (copy) { - str_ = (typename Encoding::Ch*)malloc((length + 1) * sizeof(typename Encoding::Ch)); - memcpy(const_cast(str_), str, (length + 1) * sizeof(typename Encoding::Ch)); - } - else - str_ = str; - length_ = length; - copy_ = copy; - return true; - } + bool Default() { ADD_FAILURE(); return false; } + bool String(const typename Encoding::Ch* str, size_t length, bool copy) { + EXPECT_EQ(0, str_); + if (copy) { + str_ = (typename Encoding::Ch*)malloc((length + 1) * sizeof(typename Encoding::Ch)); + memcpy(const_cast(str_), str, (length + 1) * sizeof(typename Encoding::Ch)); + } + else + str_ = str; + length_ = length; + copy_ = copy; + return true; + } - const typename Encoding::Ch* str_; - size_t length_; - bool copy_; + const typename Encoding::Ch* str_; + size_t length_; + bool copy_; }; TEST(Reader, ParseString) { #define TEST_STRING(Encoding, e, x) \ - { \ - Encoding::Ch* buffer = StrDup(x); \ - GenericInsituStringStream is(buffer); \ - ParseStringHandler h; \ - GenericReader reader; \ - reader.ParseString(is, h); \ - EXPECT_EQ(0, StrCmp(e, h.str_)); \ - EXPECT_EQ(StrLen(e), h.length_); \ - free(buffer); \ - GenericStringStream s(x); \ - ParseStringHandler h2; \ - GenericReader reader2; \ - reader2.ParseString<0>(s, h2); \ - EXPECT_EQ(0, StrCmp(e, h2.str_)); \ - EXPECT_EQ(StrLen(e), h2.length_); \ - } + { \ + Encoding::Ch* buffer = StrDup(x); \ + GenericInsituStringStream is(buffer); \ + ParseStringHandler h; \ + GenericReader reader; \ + reader.ParseString(is, h); \ + EXPECT_EQ(0, StrCmp(e, h.str_)); \ + EXPECT_EQ(StrLen(e), h.length_); \ + free(buffer); \ + GenericStringStream s(x); \ + ParseStringHandler h2; \ + GenericReader reader2; \ + reader2.ParseString<0>(s, h2); \ + EXPECT_EQ(0, StrCmp(e, h2.str_)); \ + EXPECT_EQ(StrLen(e), h2.length_); \ + } - // String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral. - // And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch. - // In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types. - // Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch. + // String constant L"\xXX" can only specify character code in bytes, which is not endianness-neutral. + // And old compiler does not support u"" and U"" string literal. So here specify string literal by array of Ch. + // In addition, GCC 4.8 generates -Wnarrowing warnings when character code >= 128 are assigned to signed integer types. + // Therefore, utype is added for declaring unsigned array, and then cast it to Encoding::Ch. #define ARRAY(...) { __VA_ARGS__ } #define TEST_STRINGARRAY(Encoding, utype, array, x) \ - { \ - static const utype ue[] = array; \ - static const Encoding::Ch* e = reinterpret_cast(&ue[0]); \ - TEST_STRING(Encoding, e, x); \ - } + { \ + static const utype ue[] = array; \ + static const Encoding::Ch* e = reinterpret_cast(&ue[0]); \ + TEST_STRING(Encoding, e, x); \ + } #define TEST_STRINGARRAY2(Encoding, utype, earray, xarray) \ - { \ - static const utype ue[] = earray; \ - static const utype xe[] = xarray; \ - static const Encoding::Ch* e = reinterpret_cast(&ue[0]); \ - static const Encoding::Ch* x = reinterpret_cast(&xe[0]); \ - TEST_STRING(Encoding, e, x); \ - } + { \ + static const utype ue[] = earray; \ + static const utype xe[] = xarray; \ + static const Encoding::Ch* e = reinterpret_cast(&ue[0]); \ + static const Encoding::Ch* x = reinterpret_cast(&xe[0]); \ + TEST_STRING(Encoding, e, x); \ + } - TEST_STRING(UTF8<>, "", "\"\""); - TEST_STRING(UTF8<>, "Hello", "\"Hello\""); - TEST_STRING(UTF8<>, "Hello\nWorld", "\"Hello\\nWorld\""); - TEST_STRING(UTF8<>, "\"\\/\b\f\n\r\t", "\"\\\"\\\\/\\b\\f\\n\\r\\t\""); - TEST_STRING(UTF8<>, "\x24", "\"\\u0024\""); // Dollar sign U+0024 - TEST_STRING(UTF8<>, "\xC2\xA2", "\"\\u00A2\""); // Cents sign U+00A2 - TEST_STRING(UTF8<>, "\xE2\x82\xAC", "\"\\u20AC\""); // Euro sign U+20AC - TEST_STRING(UTF8<>, "\xF0\x9D\x84\x9E", "\"\\uD834\\uDD1E\""); // G clef sign U+1D11E + TEST_STRING(UTF8<>, "", "\"\""); + TEST_STRING(UTF8<>, "Hello", "\"Hello\""); + TEST_STRING(UTF8<>, "Hello\nWorld", "\"Hello\\nWorld\""); + TEST_STRING(UTF8<>, "\"\\/\b\f\n\r\t", "\"\\\"\\\\/\\b\\f\\n\\r\\t\""); + TEST_STRING(UTF8<>, "\x24", "\"\\u0024\""); // Dollar sign U+0024 + TEST_STRING(UTF8<>, "\xC2\xA2", "\"\\u00A2\""); // Cents sign U+00A2 + TEST_STRING(UTF8<>, "\xE2\x82\xAC", "\"\\u20AC\""); // Euro sign U+20AC + TEST_STRING(UTF8<>, "\xF0\x9D\x84\x9E", "\"\\uD834\\uDD1E\""); // G clef sign U+1D11E - // UTF16 - TEST_STRING(UTF16<>, L"", L"\"\""); - TEST_STRING(UTF16<>, L"Hello", L"\"Hello\""); - TEST_STRING(UTF16<>, L"Hello\nWorld", L"\"Hello\\nWorld\""); - TEST_STRING(UTF16<>, L"\"\\/\b\f\n\r\t", L"\"\\\"\\\\/\\b\\f\\n\\r\\t\""); - TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x0024, 0x0000), L"\"\\u0024\""); - TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x00A2, 0x0000), L"\"\\u00A2\""); // Cents sign U+00A2 - TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x20AC, 0x0000), L"\"\\u20AC\""); // Euro sign U+20AC - TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0xD834, 0xDD1E, 0x0000), L"\"\\uD834\\uDD1E\""); // G clef sign U+1D11E + // UTF16 + TEST_STRING(UTF16<>, L"", L"\"\""); + TEST_STRING(UTF16<>, L"Hello", L"\"Hello\""); + TEST_STRING(UTF16<>, L"Hello\nWorld", L"\"Hello\\nWorld\""); + TEST_STRING(UTF16<>, L"\"\\/\b\f\n\r\t", L"\"\\\"\\\\/\\b\\f\\n\\r\\t\""); + TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x0024, 0x0000), L"\"\\u0024\""); + TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x00A2, 0x0000), L"\"\\u00A2\""); // Cents sign U+00A2 + TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0x20AC, 0x0000), L"\"\\u20AC\""); // Euro sign U+20AC + TEST_STRINGARRAY(UTF16<>, wchar_t, ARRAY(0xD834, 0xDD1E, 0x0000), L"\"\\uD834\\uDD1E\""); // G clef sign U+1D11E - // UTF32 - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\0'), ARRAY('\"', '\"', '\0')); - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\"', '\0')); - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\n', 'W', 'o', 'r', 'l', 'd', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\\', 'n', 'W', 'o', 'r', 'l', 'd', '\"', '\0')); - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\"', '\\', '/', '\b', '\f', '\n', '\r', '\t', '\0'), ARRAY('\"', '\\', '\"', '\\', '\\', '/', '\\', 'b', '\\', 'f', '\\', 'n', '\\', 'r', '\\', 't', '\"', '\0')); - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x00024, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', '2', '4', '\"', '\0')); - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x000A2, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', 'A', '2', '\"', '\0')); // Cents sign U+00A2 - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x020AC, 0x0000), ARRAY('\"', '\\', 'u', '2', '0', 'A', 'C', '\"', '\0')); // Euro sign U+20AC - TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x1D11E, 0x0000), ARRAY('\"', '\\', 'u', 'D', '8', '3', '4', '\\', 'u', 'D', 'D', '1', 'E', '\"', '\0')); // G clef sign U+1D11E + // UTF32 + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\0'), ARRAY('\"', '\"', '\0')); + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\"', '\0')); + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('H', 'e', 'l', 'l', 'o', '\n', 'W', 'o', 'r', 'l', 'd', '\0'), ARRAY('\"', 'H', 'e', 'l', 'l', 'o', '\\', 'n', 'W', 'o', 'r', 'l', 'd', '\"', '\0')); + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY('\"', '\\', '/', '\b', '\f', '\n', '\r', '\t', '\0'), ARRAY('\"', '\\', '\"', '\\', '\\', '/', '\\', 'b', '\\', 'f', '\\', 'n', '\\', 'r', '\\', 't', '\"', '\0')); + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x00024, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', '2', '4', '\"', '\0')); + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x000A2, 0x0000), ARRAY('\"', '\\', 'u', '0', '0', 'A', '2', '\"', '\0')); // Cents sign U+00A2 + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x020AC, 0x0000), ARRAY('\"', '\\', 'u', '2', '0', 'A', 'C', '\"', '\0')); // Euro sign U+20AC + TEST_STRINGARRAY2(UTF32<>, unsigned, ARRAY(0x1D11E, 0x0000), ARRAY('\"', '\\', 'u', 'D', '8', '3', '4', '\\', 'u', 'D', 'D', '1', 'E', '\"', '\0')); // G clef sign U+1D11E #undef TEST_STRINGARRAY #undef ARRAY #undef TEST_STRING - // Support of null character in string - { - StringStream s("\"Hello\\u0000World\""); - const char e[] = "Hello\0World"; - ParseStringHandler > h; - Reader reader; - reader.ParseString<0>(s, h); - EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1)); - EXPECT_EQ(11u, h.length_); - } + // Support of null character in string + { + StringStream s("\"Hello\\u0000World\""); + const char e[] = "Hello\0World"; + ParseStringHandler > h; + Reader reader; + reader.ParseString<0>(s, h); + EXPECT_EQ(0, memcmp(e, h.str_, h.length_ + 1)); + EXPECT_EQ(11u, h.length_); + } } TEST(Reader, ParseString_Transcoding) { - const char* x = "\"Hello\""; - const wchar_t* e = L"Hello"; - GenericStringStream > is(x); - GenericReader, UTF16<> > reader; - ParseStringHandler > h; - reader.ParseString<0>(is, h); - EXPECT_EQ(0, StrCmp::Ch>(e, h.str_)); - EXPECT_EQ(StrLen(e), h.length_); + const char* x = "\"Hello\""; + const wchar_t* e = L"Hello"; + GenericStringStream > is(x); + GenericReader, UTF16<> > reader; + ParseStringHandler > h; + reader.ParseString<0>(is, h); + EXPECT_EQ(0, StrCmp::Ch>(e, h.str_)); + EXPECT_EQ(StrLen(e), h.length_); } TEST(Reader, ParseString_NonDestructive) { - StringStream s("\"Hello\\nWorld\""); - ParseStringHandler > h; - Reader reader; - reader.ParseString<0>(s, h); - EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_)); - EXPECT_EQ(11u, h.length_); + StringStream s("\"Hello\\nWorld\""); + ParseStringHandler > h; + Reader reader; + reader.ParseString<0>(s, h); + EXPECT_EQ(0, StrCmp("Hello\nWorld", h.str_)); + EXPECT_EQ(11u, h.length_); } ParseErrorCode TestString(const char* str) { - StringStream s(str); - BaseReaderHandler<> h; - Reader reader; - reader.Parse(s, h); - return reader.GetParseErrorCode(); + StringStream s(str); + BaseReaderHandler<> h; + Reader reader; + reader.Parse(s, h); + return reader.GetParseErrorCode(); } TEST(Reader, ParseString_Error) { #define TEST_STRING_ERROR(errorCode, str)\ - EXPECT_EQ(errorCode, TestString(str)) + EXPECT_EQ(errorCode, TestString(str)) #define ARRAY(...) { __VA_ARGS__ } #define TEST_STRINGENCODING_ERROR(Encoding, utype, array) \ - { \ - static const utype ue[] = array; \ - static const Encoding::Ch* e = reinterpret_cast(&ue[0]); \ - EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\ - } + { \ + static const utype ue[] = array; \ + static const Encoding::Ch* e = reinterpret_cast(&ue[0]); \ + EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\ + } - // Invalid escape character in string. - TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]"); + // Invalid escape character in string. + TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]"); - // Incorrect hex digit after \\u escape in string. - TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]"); + // Incorrect hex digit after \\u escape in string. + TEST_STRING_ERROR(kParseErrorStringUnicodeEscapeInvalidHex, "[\"\\uABCG\"]"); - // The surrogate pair in string is invalid. - TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]"); - TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]"); + // The surrogate pair in string is invalid. + TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800X\"]"); + TEST_STRING_ERROR(kParseErrorStringUnicodeSurrogateInvalid, "[\"\\uD800\\uFFFF\"]"); - // Missing a closing quotation mark in string. - TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]"); + // Missing a closing quotation mark in string. + TEST_STRING_ERROR(kParseErrorStringMissQuotationMark, "[\"Test]"); - // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt + // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt - // 3 Malformed sequences + // 3 Malformed sequences - // 3.1 Unexpected continuation bytes - { - char e[] = { '[', '\"', 0, '\"', ']', '\0' }; - for (unsigned char c = 0x80u; c <= 0xBFu; c++) { - e[2] = c; - ParseErrorCode error = TestString(e); - EXPECT_EQ(kParseErrorStringInvalidEncoding, error); - if (error != kParseErrorStringInvalidEncoding) - std::cout << (unsigned)(unsigned char)c << std::endl; - } - } + // 3.1 Unexpected continuation bytes + { + char e[] = { '[', '\"', 0, '\"', ']', '\0' }; + for (unsigned char c = 0x80u; c <= 0xBFu; c++) { + e[2] = c; + ParseErrorCode error = TestString(e); + EXPECT_EQ(kParseErrorStringInvalidEncoding, error); + if (error != kParseErrorStringInvalidEncoding) + std::cout << (unsigned)(unsigned char)c << std::endl; + } + } - // 3.2 Lonely start characters, 3.5 Impossible bytes - { - char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' }; - for (unsigned c = 0xC0u; c <= 0xFFu; c++) { - e[2] = (char)c; - TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e); - } - } + // 3.2 Lonely start characters, 3.5 Impossible bytes + { + char e[] = { '[', '\"', 0, ' ', '\"', ']', '\0' }; + for (unsigned c = 0xC0u; c <= 0xFFu; c++) { + e[2] = (char)c; + TEST_STRING_ERROR(kParseErrorStringInvalidEncoding, e); + } + } - // 4 Overlong sequences + // 4 Overlong sequences - // 4.1 Examples of an overlong ASCII character - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); + // 4.1 Examples of an overlong ASCII character + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0xAFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0xAFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0xAFu, '\"', ']', '\0')); - // 4.2 Maximum overlong sequences - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0')); + // 4.2 Maximum overlong sequences + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC1u, 0xBFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x9Fu, 0xBFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x8Fu, 0xBFu, 0xBFu, '\"', ']', '\0')); - // 4.3 Overlong representation of the NUL character - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0')); + // 4.3 Overlong representation of the NUL character + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xC0u, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xE0u, 0x80u, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xF0u, 0x80u, 0x80u, 0x80u, '\"', ']', '\0')); - // 5 Illegal code positions + // 5 Illegal code positions - // 5.1 Single UTF-16 surrogates - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0')); - TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0')); + // 5.1 Single UTF-16 surrogates + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xA0u, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xADu, 0xBFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAEu, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xAFu, 0xBFu, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xB0u, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBEu, 0x80u, '\"', ']', '\0')); + TEST_STRINGENCODING_ERROR(UTF8<>, unsigned char, ARRAY('[', '\"', 0xEDu, 0xBFu, 0xBFu, '\"', ']', '\0')); #undef ARRAY #undef TEST_STRINGARRAY_ERROR @@ -412,264 +432,264 @@ TEST(Reader, ParseString_Error) { template struct ParseArrayHandler : BaseReaderHandler<> { - ParseArrayHandler() : step_(0) {} + ParseArrayHandler() : step_(0) {} - bool Default() { ADD_FAILURE(); return false; } - bool Uint(unsigned i) { EXPECT_EQ(step_, i); step_++; return true; } - bool StartArray() { EXPECT_EQ(0u, step_); step_++; return true; } - bool EndArray(SizeType) { step_++; return true; } + bool Default() { ADD_FAILURE(); return false; } + bool Uint(unsigned i) { EXPECT_EQ(step_, i); step_++; return true; } + bool StartArray() { EXPECT_EQ(0u, step_); step_++; return true; } + bool EndArray(SizeType) { step_++; return true; } - unsigned step_; + unsigned step_; }; TEST(Reader, ParseEmptyArray) { - char *json = StrDup("[ ] "); - InsituStringStream s(json); - ParseArrayHandler<0> h; - Reader reader; - reader.ParseArray<0>(s, h); - EXPECT_EQ(2u, h.step_); - free(json); + char *json = StrDup("[ ] "); + InsituStringStream s(json); + ParseArrayHandler<0> h; + Reader reader; + reader.ParseArray<0>(s, h); + EXPECT_EQ(2u, h.step_); + free(json); } TEST(Reader, ParseArray) { - char *json = StrDup("[1, 2, 3, 4]"); - InsituStringStream s(json); - ParseArrayHandler<4> h; - Reader reader; - reader.ParseArray<0>(s, h); - EXPECT_EQ(6u, h.step_); - free(json); + char *json = StrDup("[1, 2, 3, 4]"); + InsituStringStream s(json); + ParseArrayHandler<4> h; + Reader reader; + reader.ParseArray<0>(s, h); + EXPECT_EQ(6u, h.step_); + free(json); } TEST(Reader, ParseArray_Error) { #define TEST_ARRAY_ERROR(errorCode, str) \ - { \ - char buffer[1001]; \ - strncpy(buffer, str, 1000); \ - InsituStringStream s(buffer); \ - BaseReaderHandler<> h; \ - GenericReader, UTF8<>, CrtAllocator> reader; \ - EXPECT_FALSE(reader.Parse<0>(s, h)); \ - EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ - } + { \ + char buffer[1001]; \ + strncpy(buffer, str, 1000); \ + InsituStringStream s(buffer); \ + BaseReaderHandler<> h; \ + GenericReader, UTF8<>, CrtAllocator> reader; \ + EXPECT_FALSE(reader.Parse<0>(s, h)); \ + EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ + } - // Missing a comma or ']' after an array element. - TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1"); - TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}"); - TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]"); + // Missing a comma or ']' after an array element. + TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1"); + TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1}"); + TEST_ARRAY_ERROR(kParseErrorArrayMissCommaOrSquareBracket, "[1 2]"); #undef TEST_ARRAY_ERROR } struct ParseObjectHandler : BaseReaderHandler<> { - ParseObjectHandler() : step_(0) {} + ParseObjectHandler() : step_(0) {} - bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } - bool Bool(bool b) { - switch(step_) { - case 4: EXPECT_TRUE(b); step_++; return true; - case 6: EXPECT_FALSE(b); step_++; return true; - default: ADD_FAILURE(); return false; - } - } - bool Int(int i) { - switch(step_) { - case 10: EXPECT_EQ(123, i); step_++; return true; - case 15: EXPECT_EQ(1, i); step_++; return true; - case 16: EXPECT_EQ(2, i); step_++; return true; - case 17: EXPECT_EQ(3, i); step_++; return true; - default: ADD_FAILURE(); return false; - } - } - bool Uint(unsigned i) { return Int(i); } - bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_EQ(3.1416, d); step_++; return true; } - bool String(const char* str, size_t, bool) { - switch(step_) { - case 1: EXPECT_STREQ("hello", str); step_++; return true; - case 2: EXPECT_STREQ("world", str); step_++; return true; - case 3: EXPECT_STREQ("t", str); step_++; return true; - case 5: EXPECT_STREQ("f", str); step_++; return true; - case 7: EXPECT_STREQ("n", str); step_++; return true; - case 9: EXPECT_STREQ("i", str); step_++; return true; - case 11: EXPECT_STREQ("pi", str); step_++; return true; - case 13: EXPECT_STREQ("a", str); step_++; return true; - default: ADD_FAILURE(); return false; - } - } - bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } - bool EndObject(SizeType memberCount) { EXPECT_EQ(19u, step_); EXPECT_EQ(7u, memberCount); step_++; return true; } - bool StartArray() { EXPECT_EQ(14u, step_); step_++; return true; } - bool EndArray(SizeType elementCount) { EXPECT_EQ(18u, step_); EXPECT_EQ(3u, elementCount); step_++; return true; } + bool Null() { EXPECT_EQ(8u, step_); step_++; return true; } + bool Bool(bool b) { + switch(step_) { + case 4: EXPECT_TRUE(b); step_++; return true; + case 6: EXPECT_FALSE(b); step_++; return true; + default: ADD_FAILURE(); return false; + } + } + bool Int(int i) { + switch(step_) { + case 10: EXPECT_EQ(123, i); step_++; return true; + case 15: EXPECT_EQ(1, i); step_++; return true; + case 16: EXPECT_EQ(2, i); step_++; return true; + case 17: EXPECT_EQ(3, i); step_++; return true; + default: ADD_FAILURE(); return false; + } + } + bool Uint(unsigned i) { return Int(i); } + bool Double(double d) { EXPECT_EQ(12u, step_); EXPECT_EQ(3.1416, d); step_++; return true; } + bool String(const char* str, size_t, bool) { + switch(step_) { + case 1: EXPECT_STREQ("hello", str); step_++; return true; + case 2: EXPECT_STREQ("world", str); step_++; return true; + case 3: EXPECT_STREQ("t", str); step_++; return true; + case 5: EXPECT_STREQ("f", str); step_++; return true; + case 7: EXPECT_STREQ("n", str); step_++; return true; + case 9: EXPECT_STREQ("i", str); step_++; return true; + case 11: EXPECT_STREQ("pi", str); step_++; return true; + case 13: EXPECT_STREQ("a", str); step_++; return true; + default: ADD_FAILURE(); return false; + } + } + bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } + bool EndObject(SizeType memberCount) { EXPECT_EQ(19u, step_); EXPECT_EQ(7u, memberCount); step_++; return true; } + bool StartArray() { EXPECT_EQ(14u, step_); step_++; return true; } + bool EndArray(SizeType elementCount) { EXPECT_EQ(18u, step_); EXPECT_EQ(3u, elementCount); step_++; return true; } - unsigned step_; + unsigned step_; }; TEST(Reader, ParseObject) { - const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; + const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; - // Insitu - { - char* json2 = StrDup(json); - InsituStringStream s(json2); - ParseObjectHandler h; - Reader reader; - reader.ParseObject(s, h); - EXPECT_EQ(20u, h.step_); - free(json2); - } + // Insitu + { + char* json2 = StrDup(json); + InsituStringStream s(json2); + ParseObjectHandler h; + Reader reader; + reader.ParseObject(s, h); + EXPECT_EQ(20u, h.step_); + free(json2); + } - // Normal - { - StringStream s(json); - ParseObjectHandler h; - Reader reader; - reader.ParseObject<0>(s, h); - EXPECT_EQ(20u, h.step_); - } + // Normal + { + StringStream s(json); + ParseObjectHandler h; + Reader reader; + reader.ParseObject<0>(s, h); + EXPECT_EQ(20u, h.step_); + } } struct ParseEmptyObjectHandler : BaseReaderHandler<> { - ParseEmptyObjectHandler() : step_(0) {} + ParseEmptyObjectHandler() : step_(0) {} - bool Default() { ADD_FAILURE(); return false; } - bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } - bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; } + bool Default() { ADD_FAILURE(); return false; } + bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } + bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; } - unsigned step_; + unsigned step_; }; TEST(Reader, Parse_EmptyObject) { - StringStream s("{ } "); - ParseEmptyObjectHandler h; - Reader reader; - reader.ParseObject<0>(s, h); - EXPECT_EQ(2u, h.step_); + StringStream s("{ } "); + ParseEmptyObjectHandler h; + Reader reader; + reader.ParseObject<0>(s, h); + EXPECT_EQ(2u, h.step_); } struct ParseMultipleRootHandler : BaseReaderHandler<> { - ParseMultipleRootHandler() : step_(0) {} + ParseMultipleRootHandler() : step_(0) {} - bool Default() { ADD_FAILURE(); return false; } - bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } - bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; } - bool StartArray() { EXPECT_EQ(2u, step_); step_++; return true; } - bool EndArray(SizeType) { EXPECT_EQ(3u, step_); step_++; return true; } + bool Default() { ADD_FAILURE(); return false; } + bool StartObject() { EXPECT_EQ(0u, step_); step_++; return true; } + bool EndObject(SizeType) { EXPECT_EQ(1u, step_); step_++; return true; } + bool StartArray() { EXPECT_EQ(2u, step_); step_++; return true; } + bool EndArray(SizeType) { EXPECT_EQ(3u, step_); step_++; return true; } - unsigned step_; + unsigned step_; }; template void TestMultipleRoot() { - StringStream s("{}[] a"); - ParseMultipleRootHandler h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - EXPECT_EQ(2u, h.step_); - EXPECT_TRUE(reader.Parse(s, h)); - EXPECT_EQ(4u, h.step_); - EXPECT_EQ(' ', s.Take()); - EXPECT_EQ('a', s.Take()); + StringStream s("{}[] a"); + ParseMultipleRootHandler h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(2u, h.step_); + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(4u, h.step_); + EXPECT_EQ(' ', s.Take()); + EXPECT_EQ('a', s.Take()); } TEST(Reader, Parse_MultipleRoot) { - TestMultipleRoot(); + TestMultipleRoot(); } TEST(Reader, ParseIterative_MultipleRoot) { - TestMultipleRoot(); + TestMultipleRoot(); } template void TestInsituMultipleRoot() { - char* buffer = strdup("{}[] a"); - InsituStringStream s(buffer); - ParseMultipleRootHandler h; - Reader reader; - EXPECT_TRUE(reader.Parse(s, h)); - EXPECT_EQ(2u, h.step_); - EXPECT_TRUE(reader.Parse(s, h)); - EXPECT_EQ(4u, h.step_); - EXPECT_EQ(' ', s.Take()); - EXPECT_EQ('a', s.Take()); - free(buffer); + char* buffer = strdup("{}[] a"); + InsituStringStream s(buffer); + ParseMultipleRootHandler h; + Reader reader; + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(2u, h.step_); + EXPECT_TRUE(reader.Parse(s, h)); + EXPECT_EQ(4u, h.step_); + EXPECT_EQ(' ', s.Take()); + EXPECT_EQ('a', s.Take()); + free(buffer); } TEST(Reader, ParseInsitu_MultipleRoot) { - TestInsituMultipleRoot(); + TestInsituMultipleRoot(); } TEST(Reader, ParseInsituIterative_MultipleRoot) { - TestInsituMultipleRoot(); + TestInsituMultipleRoot(); } #define TEST_ERROR(errorCode, str) \ - { \ - char buffer[1001]; \ - strncpy(buffer, str, 1000); \ - InsituStringStream s(buffer); \ - BaseReaderHandler<> h; \ - Reader reader; \ - EXPECT_FALSE(reader.Parse<0>(s, h)); \ - EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ - } + { \ + char buffer[1001]; \ + strncpy(buffer, str, 1000); \ + InsituStringStream s(buffer); \ + BaseReaderHandler<> h; \ + Reader reader; \ + EXPECT_FALSE(reader.Parse<0>(s, h)); \ + EXPECT_EQ(errorCode, reader.GetParseErrorCode());\ + } TEST(Reader, ParseDocument_Error) { - // The document is empty. - TEST_ERROR(kParseErrorDocumentEmpty, ""); - TEST_ERROR(kParseErrorDocumentEmpty, " "); - TEST_ERROR(kParseErrorDocumentEmpty, " \n"); + // The document is empty. + TEST_ERROR(kParseErrorDocumentEmpty, ""); + TEST_ERROR(kParseErrorDocumentEmpty, " "); + TEST_ERROR(kParseErrorDocumentEmpty, " \n"); - // The document root must be either object or array. - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "null"); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "true"); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "false"); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "\"s\""); - TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "0"); + // The document root must be either object or array. + TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "null"); + TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "true"); + TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "false"); + TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "\"s\""); + TEST_ERROR(kParseErrorDocumentRootNotObjectOrArray, "0"); - // The document root must not follow by other values. - TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0"); - TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0"); + // The document root must not follow by other values. + TEST_ERROR(kParseErrorDocumentRootNotSingular, "[] 0"); + TEST_ERROR(kParseErrorDocumentRootNotSingular, "{} 0"); } TEST(Reader, ParseValue_Error) { - // Invalid value. - TEST_ERROR(kParseErrorValueInvalid, "[nulL]"); - TEST_ERROR(kParseErrorValueInvalid, "[truE]"); - TEST_ERROR(kParseErrorValueInvalid, "[falsE]"); - TEST_ERROR(kParseErrorValueInvalid, "[a]"); - TEST_ERROR(kParseErrorValueInvalid, "[.1]"); + // Invalid value. + TEST_ERROR(kParseErrorValueInvalid, "[nulL]"); + TEST_ERROR(kParseErrorValueInvalid, "[truE]"); + TEST_ERROR(kParseErrorValueInvalid, "[falsE]"); + TEST_ERROR(kParseErrorValueInvalid, "[a]"); + TEST_ERROR(kParseErrorValueInvalid, "[.1]"); } TEST(Reader, ParseObject_Error) { - // Missing a name for object member. - TEST_ERROR(kParseErrorObjectMissName, "{1}"); - TEST_ERROR(kParseErrorObjectMissName, "{:1}"); - TEST_ERROR(kParseErrorObjectMissName, "{null:1}"); - TEST_ERROR(kParseErrorObjectMissName, "{true:1}"); - TEST_ERROR(kParseErrorObjectMissName, "{false:1}"); - TEST_ERROR(kParseErrorObjectMissName, "{1:1}"); - TEST_ERROR(kParseErrorObjectMissName, "{[]:1}"); - TEST_ERROR(kParseErrorObjectMissName, "{{}:1}"); - TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}"); + // Missing a name for object member. + TEST_ERROR(kParseErrorObjectMissName, "{1}"); + TEST_ERROR(kParseErrorObjectMissName, "{:1}"); + TEST_ERROR(kParseErrorObjectMissName, "{null:1}"); + TEST_ERROR(kParseErrorObjectMissName, "{true:1}"); + TEST_ERROR(kParseErrorObjectMissName, "{false:1}"); + TEST_ERROR(kParseErrorObjectMissName, "{1:1}"); + TEST_ERROR(kParseErrorObjectMissName, "{[]:1}"); + TEST_ERROR(kParseErrorObjectMissName, "{{}:1}"); + TEST_ERROR(kParseErrorObjectMissName, "{xyz:1}"); - // Missing a colon after a name of object member. - TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}"); - TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}"); + // Missing a colon after a name of object member. + TEST_ERROR(kParseErrorObjectMissColon, "{\"a\" 1}"); + TEST_ERROR(kParseErrorObjectMissColon, "{\"a\",1}"); - // Must be a comma or '}' after an object member - TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]"); + // Must be a comma or '}' after an object member + TEST_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, "{\"a\":1]"); } #undef TEST_ERROR TEST(Reader, SkipWhitespace) { - StringStream ss(" A \t\tB\n \n\nC\r\r \rD \t\n\r E"); - const char* expected = "ABCDE"; - for (size_t i = 0; i < 5; i++) { - SkipWhitespace(ss); - EXPECT_EQ(expected[i], ss.Take()); - } + StringStream ss(" A \t\tB\n \n\nC\r\r \rD \t\n\r E"); + const char* expected = "ABCDE"; + for (size_t i = 0; i < 5; i++) { + SkipWhitespace(ss); + EXPECT_EQ(expected[i], ss.Take()); + } } // Test implementing a stream without copy stream optimization. @@ -677,26 +697,26 @@ TEST(Reader, SkipWhitespace) { template class CustomStringStream { public: - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - CustomStringStream(const Ch *src) : src_(src), head_(src) {} + CustomStringStream(const Ch *src) : src_(src), head_(src) {} - Ch Peek() const { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() const { return static_cast(src_ - head_); } + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: - // Prohibit copy constructor & assignment operator. - CustomStringStream(const CustomStringStream&); - CustomStringStream& operator=(const CustomStringStream&); + // Prohibit copy constructor & assignment operator. + CustomStringStream(const CustomStringStream&); + CustomStringStream& operator=(const CustomStringStream&); - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. }; // If the following code is compiled, it should generate compilation error as predicted. @@ -706,288 +726,288 @@ namespace rapidjson { template struct StreamTraits > { - enum { copyOptimization = 1 }; + enum { copyOptimization = 1 }; }; } // namespace rapidjson #endif TEST(Reader, CustomStringStream) { - const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; - CustomStringStream > s(json); - ParseObjectHandler h; - Reader reader; - reader.ParseObject<0>(s, h); - EXPECT_EQ(20u, h.step_); + const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; + CustomStringStream > s(json); + ParseObjectHandler h; + Reader reader; + reader.ParseObject<0>(s, h); + EXPECT_EQ(20u, h.step_); } #include class IStreamWrapper { public: - typedef char Ch; + typedef char Ch; - IStreamWrapper(std::istream& is) : is_(is) {} + IStreamWrapper(std::istream& is) : is_(is) {} - Ch Peek() const { - int c = is_.peek(); - return c == std::char_traits::eof() ? '\0' : (Ch)c; - } + Ch Peek() const { + int c = is_.peek(); + return c == std::char_traits::eof() ? '\0' : (Ch)c; + } - Ch Take() { - int c = is_.get(); - return c == std::char_traits::eof() ? '\0' : (Ch)c; - } + Ch Take() { + int c = is_.get(); + return c == std::char_traits::eof() ? '\0' : (Ch)c; + } - size_t Tell() const { return (size_t)is_.tellg(); } + size_t Tell() const { return (size_t)is_.tellg(); } - Ch* PutBegin() { assert(false); return 0; } - void Put(Ch) { assert(false); } - void Flush() { assert(false); } - size_t PutEnd(Ch*) { assert(false); return 0; } + Ch* PutBegin() { assert(false); return 0; } + void Put(Ch) { assert(false); } + void Flush() { assert(false); } + size_t PutEnd(Ch*) { assert(false); return 0; } private: - IStreamWrapper(const IStreamWrapper&); - IStreamWrapper& operator=(const IStreamWrapper&); + IStreamWrapper(const IStreamWrapper&); + IStreamWrapper& operator=(const IStreamWrapper&); - std::istream& is_; + std::istream& is_; }; TEST(Reader, Parse_IStreamWrapper_StringStream) { - const char* json = "[1,2,3,4]"; + const char* json = "[1,2,3,4]"; - std::stringstream ss(json); - IStreamWrapper is(ss); + std::stringstream ss(json); + IStreamWrapper is(ss); - Reader reader; - ParseArrayHandler<4> h; - reader.ParseArray<0>(is, h); - EXPECT_FALSE(reader.HasParseError()); + Reader reader; + ParseArrayHandler<4> h; + reader.ParseArray<0>(is, h); + EXPECT_FALSE(reader.HasParseError()); } // Test iterative parsing. #define TESTERRORHANDLING(text, errorCode, offset)\ {\ - StringStream json(text); \ - BaseReaderHandler<> handler; \ - Reader reader; \ - reader.IterativeParse(json, handler); \ - EXPECT_TRUE(reader.HasParseError()); \ - EXPECT_EQ(errorCode, reader.GetParseErrorCode()); \ - EXPECT_EQ(offset, reader.GetErrorOffset()); \ + StringStream json(text); \ + BaseReaderHandler<> handler; \ + Reader reader; \ + reader.IterativeParse(json, handler); \ + EXPECT_TRUE(reader.HasParseError()); \ + EXPECT_EQ(errorCode, reader.GetParseErrorCode()); \ + EXPECT_EQ(offset, reader.GetErrorOffset()); \ } TEST(Reader, IterativeParsing_ErrorHandling) { - TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u); + TESTERRORHANDLING("{\"a\": a}", kParseErrorValueInvalid, 6u); - TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u); - TESTERRORHANDLING("1", kParseErrorDocumentRootNotObjectOrArray, 0u); - TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u); + TESTERRORHANDLING("", kParseErrorDocumentEmpty, 0u); + TESTERRORHANDLING("1", kParseErrorDocumentRootNotObjectOrArray, 0u); + TESTERRORHANDLING("{}{}", kParseErrorDocumentRootNotSingular, 2u); - TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u); - TESTERRORHANDLING("{\"a\", 1}", kParseErrorObjectMissColon, 4u); - TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u); - TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u); - TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u); + TESTERRORHANDLING("{1}", kParseErrorObjectMissName, 1u); + TESTERRORHANDLING("{\"a\", 1}", kParseErrorObjectMissColon, 4u); + TESTERRORHANDLING("{\"a\"}", kParseErrorObjectMissColon, 4u); + TESTERRORHANDLING("{\"a\": 1", kParseErrorObjectMissCommaOrCurlyBracket, 7u); + TESTERRORHANDLING("[1 2 3]", kParseErrorArrayMissCommaOrSquareBracket, 3u); } template > struct IterativeParsingReaderHandler { - typedef typename Encoding::Ch Ch; + typedef typename Encoding::Ch Ch; - const static int LOG_NULL = -1; - const static int LOG_BOOL = -2; - const static int LOG_INT = -3; - const static int LOG_UINT = -4; - const static int LOG_INT64 = -5; - const static int LOG_UINT64 = -6; - const static int LOG_DOUBLE = -7; - const static int LOG_STRING = -8; - const static int LOG_STARTOBJECT = -9; - const static int LOG_ENDOBJECT = -10; - const static int LOG_STARTARRAY = -11; - const static int LOG_ENDARRAY = -12; + const static int LOG_NULL = -1; + const static int LOG_BOOL = -2; + const static int LOG_INT = -3; + const static int LOG_UINT = -4; + const static int LOG_INT64 = -5; + const static int LOG_UINT64 = -6; + const static int LOG_DOUBLE = -7; + const static int LOG_STRING = -8; + const static int LOG_STARTOBJECT = -9; + const static int LOG_ENDOBJECT = -10; + const static int LOG_STARTARRAY = -11; + const static int LOG_ENDARRAY = -12; - const static size_t LogCapacity = 256; - int Logs[LogCapacity]; - size_t LogCount; + const static size_t LogCapacity = 256; + int Logs[LogCapacity]; + size_t LogCount; - IterativeParsingReaderHandler() : LogCount(0) { - } + IterativeParsingReaderHandler() : LogCount(0) { + } - bool Null() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_NULL; return true; } + bool Null() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_NULL; return true; } - bool Bool(bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_BOOL; return true; } + bool Bool(bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_BOOL; return true; } - bool Int(int) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; } + bool Int(int) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; } - bool Uint(unsigned) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; } + bool Uint(unsigned) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT; return true; } - bool Int64(int64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT64; return true; } + bool Int64(int64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_INT64; return true; } - bool Uint64(uint64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_UINT64; return true; } + bool Uint64(uint64_t) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_UINT64; return true; } - bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_DOUBLE; return true; } + bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_DOUBLE; return true; } - bool String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; } + bool String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; } - bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; } + bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; } - bool EndObject(SizeType c) { - RAPIDJSON_ASSERT(LogCount < LogCapacity); - Logs[LogCount++] = LOG_ENDOBJECT; - Logs[LogCount++] = (int)c; - return true; - } + bool EndObject(SizeType c) { + RAPIDJSON_ASSERT(LogCount < LogCapacity); + Logs[LogCount++] = LOG_ENDOBJECT; + Logs[LogCount++] = (int)c; + return true; + } - bool StartArray() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTARRAY; return true; } + bool StartArray() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTARRAY; return true; } - bool EndArray(SizeType c) { - RAPIDJSON_ASSERT(LogCount < LogCapacity); - Logs[LogCount++] = LOG_ENDARRAY; - Logs[LogCount++] = (int)c; - return true; - } + bool EndArray(SizeType c) { + RAPIDJSON_ASSERT(LogCount < LogCapacity); + Logs[LogCount++] = LOG_ENDARRAY; + Logs[LogCount++] = (int)c; + return true; + } }; TEST(Reader, IterativeParsing_General) { - { - StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]"); - Reader reader; - IterativeParsingReaderHandler<> handler; + { + StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]"); + Reader reader; + IterativeParsingReaderHandler<> handler; - ParseResult r = reader.IterativeParse(is, handler); + ParseResult r = reader.IterativeParse(is, handler); - EXPECT_FALSE(r.IsError()); - EXPECT_FALSE(reader.HasParseError()); + EXPECT_FALSE(r.IsError()); + EXPECT_FALSE(reader.HasParseError()); - int e[] = { - handler.LOG_STARTARRAY, - handler.LOG_INT, - handler.LOG_STARTOBJECT, - handler.LOG_STRING, - handler.LOG_STARTARRAY, - handler.LOG_INT, - handler.LOG_INT, - handler.LOG_ENDARRAY, 2, - handler.LOG_ENDOBJECT, 1, - handler.LOG_NULL, - handler.LOG_BOOL, - handler.LOG_BOOL, - handler.LOG_STRING, - handler.LOG_DOUBLE, - handler.LOG_ENDARRAY, 7 - }; + int e[] = { + handler.LOG_STARTARRAY, + handler.LOG_INT, + handler.LOG_STARTOBJECT, + handler.LOG_STRING, + handler.LOG_STARTARRAY, + handler.LOG_INT, + handler.LOG_INT, + handler.LOG_ENDARRAY, 2, + handler.LOG_ENDOBJECT, 1, + handler.LOG_NULL, + handler.LOG_BOOL, + handler.LOG_BOOL, + handler.LOG_STRING, + handler.LOG_DOUBLE, + handler.LOG_ENDARRAY, 7 + }; - EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); + EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); - for (size_t i = 0; i < handler.LogCount; ++i) { - EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i; - } - } + for (size_t i = 0; i < handler.LogCount; ++i) { + EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i; + } + } } TEST(Reader, IterativeParsing_Count) { - { - StringStream is("[{}, {\"k\": 1}, [1], []]"); - Reader reader; - IterativeParsingReaderHandler<> handler; + { + StringStream is("[{}, {\"k\": 1}, [1], []]"); + Reader reader; + IterativeParsingReaderHandler<> handler; - ParseResult r = reader.IterativeParse(is, handler); + ParseResult r = reader.IterativeParse(is, handler); - EXPECT_FALSE(r.IsError()); - EXPECT_FALSE(reader.HasParseError()); + EXPECT_FALSE(r.IsError()); + EXPECT_FALSE(reader.HasParseError()); - int e[] = { - handler.LOG_STARTARRAY, - handler.LOG_STARTOBJECT, - handler.LOG_ENDOBJECT, 0, - handler.LOG_STARTOBJECT, - handler.LOG_STRING, - handler.LOG_INT, - handler.LOG_ENDOBJECT, 1, - handler.LOG_STARTARRAY, - handler.LOG_INT, - handler.LOG_ENDARRAY, 1, - handler.LOG_STARTARRAY, - handler.LOG_ENDARRAY, 0, - handler.LOG_ENDARRAY, 4 - }; + int e[] = { + handler.LOG_STARTARRAY, + handler.LOG_STARTOBJECT, + handler.LOG_ENDOBJECT, 0, + handler.LOG_STARTOBJECT, + handler.LOG_STRING, + handler.LOG_INT, + handler.LOG_ENDOBJECT, 1, + handler.LOG_STARTARRAY, + handler.LOG_INT, + handler.LOG_ENDARRAY, 1, + handler.LOG_STARTARRAY, + handler.LOG_ENDARRAY, 0, + handler.LOG_ENDARRAY, 4 + }; - EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); + EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount); - for (size_t i = 0; i < handler.LogCount; ++i) { - EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i; - } - } + for (size_t i = 0; i < handler.LogCount; ++i) { + EXPECT_EQ(e[i], handler.Logs[i]) << "i = " << i; + } + } } // Test iterative parsing on kParseErrorTermination. struct HandlerTerminateAtStartObject : public IterativeParsingReaderHandler<> { - bool StartObject() { return false; } + bool StartObject() { return false; } }; struct HandlerTerminateAtStartArray : public IterativeParsingReaderHandler<> { - bool StartArray() { return false; } + bool StartArray() { return false; } }; struct HandlerTerminateAtEndObject : public IterativeParsingReaderHandler<> { - bool EndObject(SizeType) { return false; } + bool EndObject(SizeType) { return false; } }; struct HandlerTerminateAtEndArray : public IterativeParsingReaderHandler<> { - bool EndArray(SizeType) { return false; } + bool EndArray(SizeType) { return false; } }; TEST(Reader, IterativeParsing_ShortCircuit) { - { - HandlerTerminateAtStartObject handler; - Reader reader; - StringStream is("[1, {}]"); + { + HandlerTerminateAtStartObject handler; + Reader reader; + StringStream is("[1, {}]"); - ParseResult r = reader.Parse(is, handler); + ParseResult r = reader.Parse(is, handler); - EXPECT_TRUE(reader.HasParseError()); - EXPECT_EQ(kParseErrorTermination, r.Code()); - EXPECT_EQ(4u, r.Offset()); - } + EXPECT_TRUE(reader.HasParseError()); + EXPECT_EQ(kParseErrorTermination, r.Code()); + EXPECT_EQ(4u, r.Offset()); + } - { - HandlerTerminateAtStartArray handler; - Reader reader; - StringStream is("{\"a\": []}"); + { + HandlerTerminateAtStartArray handler; + Reader reader; + StringStream is("{\"a\": []}"); - ParseResult r = reader.Parse(is, handler); + ParseResult r = reader.Parse(is, handler); - EXPECT_TRUE(reader.HasParseError()); - EXPECT_EQ(kParseErrorTermination, r.Code()); - EXPECT_EQ(6u, r.Offset()); - } + EXPECT_TRUE(reader.HasParseError()); + EXPECT_EQ(kParseErrorTermination, r.Code()); + EXPECT_EQ(6u, r.Offset()); + } - { - HandlerTerminateAtEndObject handler; - Reader reader; - StringStream is("[1, {}]"); + { + HandlerTerminateAtEndObject handler; + Reader reader; + StringStream is("[1, {}]"); - ParseResult r = reader.Parse(is, handler); + ParseResult r = reader.Parse(is, handler); - EXPECT_TRUE(reader.HasParseError()); - EXPECT_EQ(kParseErrorTermination, r.Code()); - EXPECT_EQ(5u, r.Offset()); - } + EXPECT_TRUE(reader.HasParseError()); + EXPECT_EQ(kParseErrorTermination, r.Code()); + EXPECT_EQ(5u, r.Offset()); + } - { - HandlerTerminateAtEndArray handler; - Reader reader; - StringStream is("{\"a\": []}"); + { + HandlerTerminateAtEndArray handler; + Reader reader; + StringStream is("{\"a\": []}"); - ParseResult r = reader.Parse(is, handler); + ParseResult r = reader.Parse(is, handler); - EXPECT_TRUE(reader.HasParseError()); - EXPECT_EQ(kParseErrorTermination, r.Code()); - EXPECT_EQ(7u, r.Offset()); - } + EXPECT_TRUE(reader.HasParseError()); + EXPECT_EQ(kParseErrorTermination, r.Code()); + EXPECT_EQ(7u, r.Offset()); + } } #ifdef __GNUC__ diff --git a/test/unittest/unittest.cpp b/test/unittest/unittest.cpp index 1b146c3..e92bc66 100644 --- a/test/unittest/unittest.cpp +++ b/test/unittest/unittest.cpp @@ -1,10 +1,30 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" int main(int argc, char **argv) { #if _MSC_VER - _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); - //void *testWhetherMemoryLeakDetectionWorks = malloc(1); + _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); + //void *testWhetherMemoryLeakDetectionWorks = malloc(1); #endif - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/test/unittest/unittest.h b/test/unittest/unittest.h index ad87d72..0330d73 100644 --- a/test/unittest/unittest.h +++ b/test/unittest/unittest.h @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #ifndef UNITTEST_H_ #define UNITTEST_H_ @@ -28,32 +48,32 @@ template inline unsigned StrLen(const Ch* s) { - const Ch* p = s; - while (*p) p++; - return unsigned(p - s); + const Ch* p = s; + while (*p) p++; + return unsigned(p - s); } template inline int StrCmp(const Ch* s1, const Ch* s2) { - while(*s1 && (*s1 == *s2)) { s1++; s2++; } - return (unsigned)*s1 < (unsigned)*s2 ? -1 : (unsigned)*s1 > (unsigned)*s2; + while(*s1 && (*s1 == *s2)) { s1++; s2++; } + return (unsigned)*s1 < (unsigned)*s2 ? -1 : (unsigned)*s1 > (unsigned)*s2; } template inline Ch* StrDup(const Ch* str) { - size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1); - Ch* buffer = (Ch*)malloc(bufferSize); - memcpy(buffer, str, bufferSize); - return buffer; + size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1); + Ch* buffer = (Ch*)malloc(bufferSize); + memcpy(buffer, str, bufferSize); + return buffer; } inline void TempFilename(char *filename) { - filename = tmpnam(filename); + filename = tmpnam(filename); - // For Visual Studio, tmpnam() adds a backslash in front. Remove it. - if (filename[0] == '\\') - for (int i = 0; filename[i] != '\0'; i++) - filename[i] = filename[i + 1]; + // For Visual Studio, tmpnam() adds a backslash in front. Remove it. + if (filename[0] == '\\') + for (int i = 0; filename[i] != '\0'; i++) + filename[i] = filename[i + 1]; } // Use exception for catching assert @@ -63,13 +83,13 @@ inline void TempFilename(char *filename) { class AssertException : public std::exception { public: - AssertException(const char* w) : what_(w) {} - AssertException(const AssertException& other) : what_(other.what_) {} - AssertException& operator=(const AssertException& rhs) { what_ = rhs.what_; return *this; } - virtual const char* what() const throw() { return what_; } + AssertException(const char* w) : what_(w) {} + AssertException(const AssertException& other) : what_(other.what_) {} + AssertException& operator=(const AssertException& rhs) { what_ = rhs.what_; return *this; } + virtual const char* what() const throw() { return what_; } private: - const char* what_; + const char* what_; }; #define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x)) diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index 2aa6379..fa3b6b8 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" #include "rapidjson/document.h" #include @@ -5,961 +25,961 @@ using namespace rapidjson; TEST(Value, default_constructor) { - Value x; - EXPECT_EQ(kNullType, x.GetType()); - EXPECT_TRUE(x.IsNull()); + Value x; + EXPECT_EQ(kNullType, x.GetType()); + EXPECT_TRUE(x.IsNull()); - //std::cout << "sizeof(Value): " << sizeof(x) << std::endl; + //std::cout << "sizeof(Value): " << sizeof(x) << std::endl; } // Should not pass compilation //TEST(Value, copy_constructor) { -// Value x(1234); -// Value y = x; +// Value x(1234); +// Value y = x; //} TEST(Value, assignment_operator) { - Value x(1234); - Value y; - y = x; - EXPECT_TRUE(x.IsNull()); // move semantic - EXPECT_EQ(1234, y.GetInt()); + Value x(1234); + Value y; + y = x; + EXPECT_TRUE(x.IsNull()); // move semantic + EXPECT_EQ(1234, y.GetInt()); - y = 5678; - EXPECT_TRUE(y.IsInt()); - EXPECT_EQ(5678, y.GetInt()); + y = 5678; + EXPECT_TRUE(y.IsInt()); + EXPECT_EQ(5678, y.GetInt()); - x = "Hello"; - EXPECT_TRUE(x.IsString()); - EXPECT_STREQ(x.GetString(),"Hello"); + x = "Hello"; + EXPECT_TRUE(x.IsString()); + EXPECT_STREQ(x.GetString(),"Hello"); - y = StringRef(x.GetString(),x.GetStringLength()); - EXPECT_TRUE(y.IsString()); - EXPECT_EQ(y.GetString(),x.GetString()); - EXPECT_EQ(y.GetStringLength(),x.GetStringLength()); + y = StringRef(x.GetString(),x.GetStringLength()); + EXPECT_TRUE(y.IsString()); + EXPECT_EQ(y.GetString(),x.GetString()); + EXPECT_EQ(y.GetStringLength(),x.GetStringLength()); - static char mstr[] = "mutable"; - // y = mstr; // should not compile - y = StringRef(mstr); - EXPECT_TRUE(y.IsString()); - EXPECT_EQ(y.GetString(),mstr); + static char mstr[] = "mutable"; + // y = mstr; // should not compile + y = StringRef(mstr); + EXPECT_TRUE(y.IsString()); + EXPECT_EQ(y.GetString(),mstr); } template void TestEqual(const A& a, const B& b) { - EXPECT_TRUE (a == b); - EXPECT_FALSE(a != b); - EXPECT_TRUE (b == a); - EXPECT_FALSE(b != a); + EXPECT_TRUE (a == b); + EXPECT_FALSE(a != b); + EXPECT_TRUE (b == a); + EXPECT_FALSE(b != a); } template void TestUnequal(const A& a, const B& b) { - EXPECT_FALSE(a == b); - EXPECT_TRUE (a != b); - EXPECT_FALSE(b == a); - EXPECT_TRUE (b != a); + EXPECT_FALSE(a == b); + EXPECT_TRUE (a != b); + EXPECT_FALSE(b == a); + EXPECT_TRUE (b != a); } TEST(Value, equalto_operator) { - Value::AllocatorType allocator; - Value x(kObjectType); - x.AddMember("hello", "world", allocator) - .AddMember("t", Value(true).Move(), allocator) - .AddMember("f", Value(false).Move(), allocator) - .AddMember("n", Value(kNullType).Move(), allocator) - .AddMember("i", 123, allocator) - .AddMember("pi", 3.14, allocator) - .AddMember("a", Value(kArrayType).Move().PushBack(1, allocator).PushBack(2, allocator).PushBack(3, allocator), allocator); + Value::AllocatorType allocator; + Value x(kObjectType); + x.AddMember("hello", "world", allocator) + .AddMember("t", Value(true).Move(), allocator) + .AddMember("f", Value(false).Move(), allocator) + .AddMember("n", Value(kNullType).Move(), allocator) + .AddMember("i", 123, allocator) + .AddMember("pi", 3.14, allocator) + .AddMember("a", Value(kArrayType).Move().PushBack(1, allocator).PushBack(2, allocator).PushBack(3, allocator), allocator); - // Test templated operator==() and operator!=() - TestEqual(x["hello"], "world"); - const char* cc = "world"; - TestEqual(x["hello"], cc); - char* c = strdup("world"); - TestEqual(x["hello"], c); - free(c); + // Test templated operator==() and operator!=() + TestEqual(x["hello"], "world"); + const char* cc = "world"; + TestEqual(x["hello"], cc); + char* c = strdup("world"); + TestEqual(x["hello"], c); + free(c); - TestEqual(x["t"], true); - TestEqual(x["f"], false); - TestEqual(x["i"], 123); - TestEqual(x["pi"], 3.14); + TestEqual(x["t"], true); + TestEqual(x["f"], false); + TestEqual(x["i"], 123); + TestEqual(x["pi"], 3.14); - // Test operator==() - Value y; - y.CopyFrom(x, allocator); - TestEqual(x, y); + // Test operator==() + Value y; + y.CopyFrom(x, allocator); + TestEqual(x, y); - // Swapping member order should be fine. - y.RemoveMember("t"); - TestUnequal(x, y); - y.AddMember("t", Value(true).Move(), allocator); - TestEqual(x, y); + // Swapping member order should be fine. + y.RemoveMember("t"); + TestUnequal(x, y); + y.AddMember("t", Value(true).Move(), allocator); + TestEqual(x, y); } template void TestCopyFrom() { - typename Value::AllocatorType a; - Value v1(1234); - Value v2(v1, a); // deep copy constructor - EXPECT_TRUE(v1.GetType() == v2.GetType()); - EXPECT_EQ(v1.GetInt(), v2.GetInt()); + typename Value::AllocatorType a; + Value v1(1234); + Value v2(v1, a); // deep copy constructor + EXPECT_TRUE(v1.GetType() == v2.GetType()); + EXPECT_EQ(v1.GetInt(), v2.GetInt()); - v1.SetString("foo"); - v2.CopyFrom(v1, a); - EXPECT_TRUE(v1.GetType() == v2.GetType()); - EXPECT_STREQ(v1.GetString(), v2.GetString()); - EXPECT_EQ(v1.GetString(), v2.GetString()); // string NOT copied + v1.SetString("foo"); + v2.CopyFrom(v1, a); + EXPECT_TRUE(v1.GetType() == v2.GetType()); + EXPECT_STREQ(v1.GetString(), v2.GetString()); + EXPECT_EQ(v1.GetString(), v2.GetString()); // string NOT copied - v1.SetArray().PushBack(1234, a); - v2.CopyFrom(v1, a); - EXPECT_TRUE(v2.IsArray()); - EXPECT_EQ(v1.Size(), v2.Size()); + v1.SetArray().PushBack(1234, a); + v2.CopyFrom(v1, a); + EXPECT_TRUE(v2.IsArray()); + EXPECT_EQ(v1.Size(), v2.Size()); - v1.PushBack(Value().SetString("foo", a), a); // push string copy - EXPECT_TRUE(v1.Size() != v2.Size()); - v2.CopyFrom(v1, a); - EXPECT_TRUE(v1.Size() == v2.Size()); - EXPECT_STREQ(v1[1].GetString(), v2[1].GetString()); - EXPECT_NE(v1[1].GetString(), v2[1].GetString()); // string got copied + v1.PushBack(Value().SetString("foo", a), a); // push string copy + EXPECT_TRUE(v1.Size() != v2.Size()); + v2.CopyFrom(v1, a); + EXPECT_TRUE(v1.Size() == v2.Size()); + EXPECT_STREQ(v1[1].GetString(), v2[1].GetString()); + EXPECT_NE(v1[1].GetString(), v2[1].GetString()); // string got copied } TEST(Value, CopyFrom) { - TestCopyFrom(); - TestCopyFrom, CrtAllocator> >(); + TestCopyFrom(); + TestCopyFrom, CrtAllocator> >(); } TEST(Value, Swap) { - Value v1(1234); - Value v2(kObjectType); + Value v1(1234); + Value v2(kObjectType); - EXPECT_EQ(&v1, &v1.Swap(v2)); - EXPECT_TRUE(v1.IsObject()); - EXPECT_TRUE(v2.IsInt()); - EXPECT_EQ(1234, v2.GetInt()); + EXPECT_EQ(&v1, &v1.Swap(v2)); + EXPECT_TRUE(v1.IsObject()); + EXPECT_TRUE(v2.IsInt()); + EXPECT_EQ(1234, v2.GetInt()); } TEST(Value, Null) { - // Default constructor - Value x; - EXPECT_EQ(kNullType, x.GetType()); - EXPECT_TRUE(x.IsNull()); + // Default constructor + Value x; + EXPECT_EQ(kNullType, x.GetType()); + EXPECT_TRUE(x.IsNull()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsNumber()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsNumber()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - // Constructor with type - Value y(kNullType); - EXPECT_TRUE(y.IsNull()); + // Constructor with type + Value y(kNullType); + EXPECT_TRUE(y.IsNull()); - // SetNull(); - Value z(true); - z.SetNull(); - EXPECT_TRUE(z.IsNull()); + // SetNull(); + Value z(true); + z.SetNull(); + EXPECT_TRUE(z.IsNull()); } TEST(Value, True) { - // Constructor with bool - Value x(true); - EXPECT_EQ(kTrueType, x.GetType()); - EXPECT_TRUE(x.GetBool()); - EXPECT_TRUE(x.IsBool()); - EXPECT_TRUE(x.IsTrue()); + // Constructor with bool + Value x(true); + EXPECT_EQ(kTrueType, x.GetType()); + EXPECT_TRUE(x.GetBool()); + EXPECT_TRUE(x.IsBool()); + EXPECT_TRUE(x.IsTrue()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsNumber()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsNumber()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - // Constructor with type - Value y(kTrueType); - EXPECT_TRUE(y.IsTrue()); + // Constructor with type + Value y(kTrueType); + EXPECT_TRUE(y.IsTrue()); - // SetBool() - Value z; - z.SetBool(true); - EXPECT_TRUE(z.IsTrue()); + // SetBool() + Value z; + z.SetBool(true); + EXPECT_TRUE(z.IsTrue()); } TEST(Value, False) { - // Constructor with bool - Value x(false); - EXPECT_EQ(kFalseType, x.GetType()); - EXPECT_TRUE(x.IsBool()); - EXPECT_TRUE(x.IsFalse()); + // Constructor with bool + Value x(false); + EXPECT_EQ(kFalseType, x.GetType()); + EXPECT_TRUE(x.IsBool()); + EXPECT_TRUE(x.IsFalse()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.GetBool()); - //EXPECT_FALSE((bool)x); - EXPECT_FALSE(x.IsNumber()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.GetBool()); + //EXPECT_FALSE((bool)x); + EXPECT_FALSE(x.IsNumber()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - // Constructor with type - Value y(kFalseType); - EXPECT_TRUE(y.IsFalse()); + // Constructor with type + Value y(kFalseType); + EXPECT_TRUE(y.IsFalse()); - // SetBool() - Value z; - z.SetBool(false); - EXPECT_TRUE(z.IsFalse()); + // SetBool() + Value z; + z.SetBool(false); + EXPECT_TRUE(z.IsFalse()); } TEST(Value, Int) { - // Constructor with int - Value x(1234); - EXPECT_EQ(kNumberType, x.GetType()); - EXPECT_EQ(1234, x.GetInt()); - EXPECT_EQ(1234u, x.GetUint()); - EXPECT_EQ(1234, x.GetInt64()); - EXPECT_EQ(1234u, x.GetUint64()); - EXPECT_EQ(1234, x.GetDouble()); - //EXPECT_EQ(1234, (int)x); - //EXPECT_EQ(1234, (unsigned)x); - //EXPECT_EQ(1234, (int64_t)x); - //EXPECT_EQ(1234, (uint64_t)x); - //EXPECT_EQ(1234, (double)x); - EXPECT_TRUE(x.IsNumber()); - EXPECT_TRUE(x.IsInt()); - EXPECT_TRUE(x.IsUint()); - EXPECT_TRUE(x.IsInt64()); - EXPECT_TRUE(x.IsUint64()); + // Constructor with int + Value x(1234); + EXPECT_EQ(kNumberType, x.GetType()); + EXPECT_EQ(1234, x.GetInt()); + EXPECT_EQ(1234u, x.GetUint()); + EXPECT_EQ(1234, x.GetInt64()); + EXPECT_EQ(1234u, x.GetUint64()); + EXPECT_EQ(1234, x.GetDouble()); + //EXPECT_EQ(1234, (int)x); + //EXPECT_EQ(1234, (unsigned)x); + //EXPECT_EQ(1234, (int64_t)x); + //EXPECT_EQ(1234, (uint64_t)x); + //EXPECT_EQ(1234, (double)x); + EXPECT_TRUE(x.IsNumber()); + EXPECT_TRUE(x.IsInt()); + EXPECT_TRUE(x.IsUint()); + EXPECT_TRUE(x.IsInt64()); + EXPECT_TRUE(x.IsUint64()); - EXPECT_FALSE(x.IsDouble()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsDouble()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - Value nx(-1234); - EXPECT_EQ(-1234, nx.GetInt()); - EXPECT_EQ(-1234, nx.GetInt64()); - EXPECT_TRUE(nx.IsInt()); - EXPECT_TRUE(nx.IsInt64()); - EXPECT_FALSE(nx.IsUint()); - EXPECT_FALSE(nx.IsUint64()); + Value nx(-1234); + EXPECT_EQ(-1234, nx.GetInt()); + EXPECT_EQ(-1234, nx.GetInt64()); + EXPECT_TRUE(nx.IsInt()); + EXPECT_TRUE(nx.IsInt64()); + EXPECT_FALSE(nx.IsUint()); + EXPECT_FALSE(nx.IsUint64()); - // Constructor with type - Value y(kNumberType); - EXPECT_TRUE(y.IsNumber()); - EXPECT_TRUE(y.IsInt()); - EXPECT_EQ(0, y.GetInt()); + // Constructor with type + Value y(kNumberType); + EXPECT_TRUE(y.IsNumber()); + EXPECT_TRUE(y.IsInt()); + EXPECT_EQ(0, y.GetInt()); - // SetInt() - Value z; - z.SetInt(1234); - EXPECT_EQ(1234, z.GetInt()); + // SetInt() + Value z; + z.SetInt(1234); + EXPECT_EQ(1234, z.GetInt()); - // operator=(int) - z = 5678; - EXPECT_EQ(5678, z.GetInt()); + // operator=(int) + z = 5678; + EXPECT_EQ(5678, z.GetInt()); } TEST(Value, Uint) { - // Constructor with int - Value x(1234u); - EXPECT_EQ(kNumberType, x.GetType()); - EXPECT_EQ(1234, x.GetInt()); - EXPECT_EQ(1234u, x.GetUint()); - EXPECT_EQ(1234, x.GetInt64()); - EXPECT_EQ(1234u, x.GetUint64()); - EXPECT_TRUE(x.IsNumber()); - EXPECT_TRUE(x.IsInt()); - EXPECT_TRUE(x.IsUint()); - EXPECT_TRUE(x.IsInt64()); - EXPECT_TRUE(x.IsUint64()); - EXPECT_EQ(1234.0, x.GetDouble()); // Number can always be cast as double but !IsDouble(). + // Constructor with int + Value x(1234u); + EXPECT_EQ(kNumberType, x.GetType()); + EXPECT_EQ(1234, x.GetInt()); + EXPECT_EQ(1234u, x.GetUint()); + EXPECT_EQ(1234, x.GetInt64()); + EXPECT_EQ(1234u, x.GetUint64()); + EXPECT_TRUE(x.IsNumber()); + EXPECT_TRUE(x.IsInt()); + EXPECT_TRUE(x.IsUint()); + EXPECT_TRUE(x.IsInt64()); + EXPECT_TRUE(x.IsUint64()); + EXPECT_EQ(1234.0, x.GetDouble()); // Number can always be cast as double but !IsDouble(). - EXPECT_FALSE(x.IsDouble()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsDouble()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - // SetUint() - Value z; - z.SetUint(1234); - EXPECT_EQ(1234u, z.GetUint()); + // SetUint() + Value z; + z.SetUint(1234); + EXPECT_EQ(1234u, z.GetUint()); - // operator=(unsigned) - z = 5678u; - EXPECT_EQ(5678u, z.GetUint()); + // operator=(unsigned) + z = 5678u; + EXPECT_EQ(5678u, z.GetUint()); - z = 2147483648u; // 2^31, cannot cast as int - EXPECT_EQ(2147483648u, z.GetUint()); - EXPECT_FALSE(z.IsInt()); - EXPECT_TRUE(z.IsInt64()); // Issue 41: Incorrect parsing of unsigned int number types + z = 2147483648u; // 2^31, cannot cast as int + EXPECT_EQ(2147483648u, z.GetUint()); + EXPECT_FALSE(z.IsInt()); + EXPECT_TRUE(z.IsInt64()); // Issue 41: Incorrect parsing of unsigned int number types } TEST(Value, Int64) { - // Constructor with int - Value x(int64_t(1234LL)); - EXPECT_EQ(kNumberType, x.GetType()); - EXPECT_EQ(1234, x.GetInt()); - EXPECT_EQ(1234u, x.GetUint()); - EXPECT_EQ(1234, x.GetInt64()); - EXPECT_EQ(1234u, x.GetUint64()); - EXPECT_TRUE(x.IsNumber()); - EXPECT_TRUE(x.IsInt()); - EXPECT_TRUE(x.IsUint()); - EXPECT_TRUE(x.IsInt64()); - EXPECT_TRUE(x.IsUint64()); + // Constructor with int + Value x(int64_t(1234LL)); + EXPECT_EQ(kNumberType, x.GetType()); + EXPECT_EQ(1234, x.GetInt()); + EXPECT_EQ(1234u, x.GetUint()); + EXPECT_EQ(1234, x.GetInt64()); + EXPECT_EQ(1234u, x.GetUint64()); + EXPECT_TRUE(x.IsNumber()); + EXPECT_TRUE(x.IsInt()); + EXPECT_TRUE(x.IsUint()); + EXPECT_TRUE(x.IsInt64()); + EXPECT_TRUE(x.IsUint64()); - EXPECT_FALSE(x.IsDouble()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsDouble()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - Value nx(int64_t(-1234LL)); - EXPECT_EQ(-1234, nx.GetInt()); - EXPECT_EQ(-1234, nx.GetInt64()); - EXPECT_TRUE(nx.IsInt()); - EXPECT_TRUE(nx.IsInt64()); - EXPECT_FALSE(nx.IsUint()); - EXPECT_FALSE(nx.IsUint64()); + Value nx(int64_t(-1234LL)); + EXPECT_EQ(-1234, nx.GetInt()); + EXPECT_EQ(-1234, nx.GetInt64()); + EXPECT_TRUE(nx.IsInt()); + EXPECT_TRUE(nx.IsInt64()); + EXPECT_FALSE(nx.IsUint()); + EXPECT_FALSE(nx.IsUint64()); - // SetInt64() - Value z; - z.SetInt64(1234); - EXPECT_EQ(1234, z.GetInt64()); + // SetInt64() + Value z; + z.SetInt64(1234); + EXPECT_EQ(1234, z.GetInt64()); - z.SetInt64(2147483648LL); // 2^31, cannot cast as int - EXPECT_FALSE(z.IsInt()); - EXPECT_TRUE(z.IsUint()); + z.SetInt64(2147483648LL); // 2^31, cannot cast as int + EXPECT_FALSE(z.IsInt()); + EXPECT_TRUE(z.IsUint()); - z.SetInt64(4294967296LL); // 2^32, cannot cast as uint - EXPECT_FALSE(z.IsInt()); - EXPECT_FALSE(z.IsUint()); + z.SetInt64(4294967296LL); // 2^32, cannot cast as uint + EXPECT_FALSE(z.IsInt()); + EXPECT_FALSE(z.IsUint()); } TEST(Value, Uint64) { - // Constructor with int - Value x(uint64_t(1234LL)); - EXPECT_EQ(kNumberType, x.GetType()); - EXPECT_EQ(1234, x.GetInt()); - EXPECT_EQ(1234u, x.GetUint()); - EXPECT_EQ(1234, x.GetInt64()); - EXPECT_EQ(1234u, x.GetUint64()); - EXPECT_TRUE(x.IsNumber()); - EXPECT_TRUE(x.IsInt()); - EXPECT_TRUE(x.IsUint()); - EXPECT_TRUE(x.IsInt64()); - EXPECT_TRUE(x.IsUint64()); + // Constructor with int + Value x(uint64_t(1234LL)); + EXPECT_EQ(kNumberType, x.GetType()); + EXPECT_EQ(1234, x.GetInt()); + EXPECT_EQ(1234u, x.GetUint()); + EXPECT_EQ(1234, x.GetInt64()); + EXPECT_EQ(1234u, x.GetUint64()); + EXPECT_TRUE(x.IsNumber()); + EXPECT_TRUE(x.IsInt()); + EXPECT_TRUE(x.IsUint()); + EXPECT_TRUE(x.IsInt64()); + EXPECT_TRUE(x.IsUint64()); - EXPECT_FALSE(x.IsDouble()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsDouble()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - // SetUint64() - Value z; - z.SetUint64(1234); - EXPECT_EQ(1234u, z.GetUint64()); + // SetUint64() + Value z; + z.SetUint64(1234); + EXPECT_EQ(1234u, z.GetUint64()); - z.SetUint64(2147483648LL); // 2^31, cannot cast as int - EXPECT_FALSE(z.IsInt()); - EXPECT_TRUE(z.IsUint()); - EXPECT_TRUE(z.IsInt64()); + z.SetUint64(2147483648LL); // 2^31, cannot cast as int + EXPECT_FALSE(z.IsInt()); + EXPECT_TRUE(z.IsUint()); + EXPECT_TRUE(z.IsInt64()); - z.SetUint64(4294967296LL); // 2^32, cannot cast as uint - EXPECT_FALSE(z.IsInt()); - EXPECT_FALSE(z.IsUint()); - EXPECT_TRUE(z.IsInt64()); + z.SetUint64(4294967296LL); // 2^32, cannot cast as uint + EXPECT_FALSE(z.IsInt()); + EXPECT_FALSE(z.IsUint()); + EXPECT_TRUE(z.IsInt64()); - z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64 - EXPECT_FALSE(z.IsInt64()); + z.SetUint64(9223372036854775808uLL); // 2^63 cannot cast as int64 + EXPECT_FALSE(z.IsInt64()); - // Issue 48 - EXPECT_EQ(9223372036854775808uLL, z.GetUint64()); + // Issue 48 + EXPECT_EQ(9223372036854775808uLL, z.GetUint64()); } TEST(Value, Double) { - // Constructor with double - Value x(12.34); - EXPECT_EQ(kNumberType, x.GetType()); - EXPECT_EQ(12.34, x.GetDouble()); - EXPECT_TRUE(x.IsNumber()); - EXPECT_TRUE(x.IsDouble()); + // Constructor with double + Value x(12.34); + EXPECT_EQ(kNumberType, x.GetType()); + EXPECT_EQ(12.34, x.GetDouble()); + EXPECT_TRUE(x.IsNumber()); + EXPECT_TRUE(x.IsDouble()); - EXPECT_FALSE(x.IsInt()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsInt()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - // SetDouble() - Value z; - z.SetDouble(12.34); - EXPECT_EQ(12.34, z.GetDouble()); + // SetDouble() + Value z; + z.SetDouble(12.34); + EXPECT_EQ(12.34, z.GetDouble()); - z = 56.78; - EXPECT_EQ(56.78, z.GetDouble()); + z = 56.78; + EXPECT_EQ(56.78, z.GetDouble()); } TEST(Value, String) { - // Construction with const string - Value x("Hello", 5); // literal - EXPECT_EQ(kStringType, x.GetType()); - EXPECT_TRUE(x.IsString()); - EXPECT_STREQ("Hello", x.GetString()); - EXPECT_EQ(5u, x.GetStringLength()); + // Construction with const string + Value x("Hello", 5); // literal + EXPECT_EQ(kStringType, x.GetType()); + EXPECT_TRUE(x.IsString()); + EXPECT_STREQ("Hello", x.GetString()); + EXPECT_EQ(5u, x.GetStringLength()); - EXPECT_FALSE(x.IsNumber()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsObject()); - EXPECT_FALSE(x.IsArray()); + EXPECT_FALSE(x.IsNumber()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsArray()); - static const char cstr[] = "World"; // const array - Value(cstr).Swap(x); - EXPECT_TRUE(x.IsString()); - EXPECT_EQ(x.GetString(), cstr); - EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1); + static const char cstr[] = "World"; // const array + Value(cstr).Swap(x); + EXPECT_TRUE(x.IsString()); + EXPECT_EQ(x.GetString(), cstr); + EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1); - static char mstr[] = "Howdy"; // non-const array - // Value(mstr).Swap(x); // should not compile - Value(StringRef(mstr)).Swap(x); - EXPECT_TRUE(x.IsString()); - EXPECT_EQ(x.GetString(), mstr); - EXPECT_EQ(x.GetStringLength(), sizeof(mstr)-1); - strncpy(mstr,"Hello", sizeof(mstr)); - EXPECT_STREQ(x.GetString(), "Hello"); + static char mstr[] = "Howdy"; // non-const array + // Value(mstr).Swap(x); // should not compile + Value(StringRef(mstr)).Swap(x); + EXPECT_TRUE(x.IsString()); + EXPECT_EQ(x.GetString(), mstr); + EXPECT_EQ(x.GetStringLength(), sizeof(mstr)-1); + strncpy(mstr,"Hello", sizeof(mstr)); + EXPECT_STREQ(x.GetString(), "Hello"); - const char* pstr = cstr; - //Value(pstr).Swap(x); // should not compile - Value(StringRef(pstr)).Swap(x); - EXPECT_TRUE(x.IsString()); - EXPECT_EQ(x.GetString(), cstr); - EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1); + const char* pstr = cstr; + //Value(pstr).Swap(x); // should not compile + Value(StringRef(pstr)).Swap(x); + EXPECT_TRUE(x.IsString()); + EXPECT_EQ(x.GetString(), cstr); + EXPECT_EQ(x.GetStringLength(), sizeof(cstr)-1); - char* mpstr = mstr; - Value(StringRef(mpstr,sizeof(mstr)-1)).Swap(x); - EXPECT_TRUE(x.IsString()); - EXPECT_EQ(x.GetString(), mstr); - EXPECT_EQ(x.GetStringLength(), 5u); - EXPECT_STREQ(x.GetString(), "Hello"); + char* mpstr = mstr; + Value(StringRef(mpstr,sizeof(mstr)-1)).Swap(x); + EXPECT_TRUE(x.IsString()); + EXPECT_EQ(x.GetString(), mstr); + EXPECT_EQ(x.GetStringLength(), 5u); + EXPECT_STREQ(x.GetString(), "Hello"); - // Constructor with copy string - MemoryPoolAllocator<> allocator; - Value c(x.GetString(), x.GetStringLength(), allocator); - EXPECT_NE(x.GetString(), c.GetString()); - EXPECT_EQ(x.GetStringLength(), c.GetStringLength()); - EXPECT_STREQ(x.GetString(), c.GetString()); - //x.SetString("World"); - x.SetString("World", 5); - EXPECT_STREQ("Hello", c.GetString()); - EXPECT_EQ(5u, c.GetStringLength()); + // Constructor with copy string + MemoryPoolAllocator<> allocator; + Value c(x.GetString(), x.GetStringLength(), allocator); + EXPECT_NE(x.GetString(), c.GetString()); + EXPECT_EQ(x.GetStringLength(), c.GetStringLength()); + EXPECT_STREQ(x.GetString(), c.GetString()); + //x.SetString("World"); + x.SetString("World", 5); + EXPECT_STREQ("Hello", c.GetString()); + EXPECT_EQ(5u, c.GetStringLength()); - // Constructor with type - Value y(kStringType); - EXPECT_TRUE(y.IsString()); - EXPECT_EQ(0, y.GetString()); - EXPECT_EQ(0u, y.GetStringLength()); + // Constructor with type + Value y(kStringType); + EXPECT_TRUE(y.IsString()); + EXPECT_EQ(0, y.GetString()); + EXPECT_EQ(0u, y.GetStringLength()); - // SetConsttring() - Value z; - z.SetString("Hello"); - EXPECT_TRUE(x.IsString()); - z.SetString("Hello", 5); - EXPECT_STREQ("Hello", z.GetString()); - EXPECT_STREQ("Hello", z.GetString()); - EXPECT_EQ(5u, z.GetStringLength()); + // SetConsttring() + Value z; + z.SetString("Hello"); + EXPECT_TRUE(x.IsString()); + z.SetString("Hello", 5); + EXPECT_STREQ("Hello", z.GetString()); + EXPECT_STREQ("Hello", z.GetString()); + EXPECT_EQ(5u, z.GetStringLength()); - z.SetString("Hello"); - EXPECT_TRUE(z.IsString()); - EXPECT_STREQ("Hello", z.GetString()); + z.SetString("Hello"); + EXPECT_TRUE(z.IsString()); + EXPECT_STREQ("Hello", z.GetString()); - //z.SetString(mstr); // should not compile - //z.SetString(pstr); // should not compile - z.SetString(StringRef(mstr)); - EXPECT_TRUE(z.IsString()); - EXPECT_STREQ(z.GetString(), mstr); + //z.SetString(mstr); // should not compile + //z.SetString(pstr); // should not compile + z.SetString(StringRef(mstr)); + EXPECT_TRUE(z.IsString()); + EXPECT_STREQ(z.GetString(), mstr); - z.SetString(cstr); - EXPECT_TRUE(z.IsString()); - EXPECT_EQ(cstr, z.GetString()); + z.SetString(cstr); + EXPECT_TRUE(z.IsString()); + EXPECT_EQ(cstr, z.GetString()); - z = cstr; - EXPECT_TRUE(z.IsString()); - EXPECT_EQ(cstr, z.GetString()); + z = cstr; + EXPECT_TRUE(z.IsString()); + EXPECT_EQ(cstr, z.GetString()); - // SetString() - char s[] = "World"; - Value w; - w.SetString(s, (SizeType)strlen(s), allocator); - s[0] = '\0'; - EXPECT_STREQ("World", w.GetString()); - EXPECT_EQ(5u, w.GetStringLength()); + // SetString() + char s[] = "World"; + Value w; + w.SetString(s, (SizeType)strlen(s), allocator); + s[0] = '\0'; + EXPECT_STREQ("World", w.GetString()); + EXPECT_EQ(5u, w.GetStringLength()); } TEST(Value, Array) { - Value x(kArrayType); - const Value& y = x; - Value::AllocatorType allocator; + Value x(kArrayType); + const Value& y = x; + Value::AllocatorType allocator; - EXPECT_EQ(kArrayType, x.GetType()); - EXPECT_TRUE(x.IsArray()); - EXPECT_TRUE(x.Empty()); - EXPECT_EQ(0u, x.Size()); - EXPECT_TRUE(y.IsArray()); - EXPECT_TRUE(y.Empty()); - EXPECT_EQ(0u, y.Size()); + EXPECT_EQ(kArrayType, x.GetType()); + EXPECT_TRUE(x.IsArray()); + EXPECT_TRUE(x.Empty()); + EXPECT_EQ(0u, x.Size()); + EXPECT_TRUE(y.IsArray()); + EXPECT_TRUE(y.Empty()); + EXPECT_EQ(0u, y.Size()); - EXPECT_FALSE(x.IsNull()); - EXPECT_FALSE(x.IsBool()); - EXPECT_FALSE(x.IsFalse()); - EXPECT_FALSE(x.IsTrue()); - EXPECT_FALSE(x.IsString()); - EXPECT_FALSE(x.IsObject()); + EXPECT_FALSE(x.IsNull()); + EXPECT_FALSE(x.IsBool()); + EXPECT_FALSE(x.IsFalse()); + EXPECT_FALSE(x.IsTrue()); + EXPECT_FALSE(x.IsString()); + EXPECT_FALSE(x.IsObject()); - // PushBack() - Value v; - x.PushBack(v, allocator); - v.SetBool(true); - x.PushBack(v, allocator); - v.SetBool(false); - x.PushBack(v, allocator); - v.SetInt(123); - x.PushBack(v, allocator); - //x.PushBack((const char*)"foo", allocator); // should not compile - x.PushBack("foo", allocator); + // PushBack() + Value v; + x.PushBack(v, allocator); + v.SetBool(true); + x.PushBack(v, allocator); + v.SetBool(false); + x.PushBack(v, allocator); + v.SetInt(123); + x.PushBack(v, allocator); + //x.PushBack((const char*)"foo", allocator); // should not compile + x.PushBack("foo", allocator); - EXPECT_FALSE(x.Empty()); - EXPECT_EQ(5u, x.Size()); - EXPECT_FALSE(y.Empty()); - EXPECT_EQ(5u, y.Size()); - EXPECT_TRUE(x[SizeType(0)].IsNull()); - EXPECT_TRUE(x[1u].IsTrue()); - EXPECT_TRUE(x[2u].IsFalse()); - EXPECT_TRUE(x[3u].IsInt()); - EXPECT_EQ(123, x[3u].GetInt()); - EXPECT_TRUE(y[SizeType(0)].IsNull()); - EXPECT_TRUE(y[1u].IsTrue()); - EXPECT_TRUE(y[2u].IsFalse()); - EXPECT_TRUE(y[3u].IsInt()); - EXPECT_EQ(123, y[3u].GetInt()); - EXPECT_TRUE(y[4u].IsString()); - EXPECT_STREQ("foo", y[4u].GetString()); + EXPECT_FALSE(x.Empty()); + EXPECT_EQ(5u, x.Size()); + EXPECT_FALSE(y.Empty()); + EXPECT_EQ(5u, y.Size()); + EXPECT_TRUE(x[SizeType(0)].IsNull()); + EXPECT_TRUE(x[1u].IsTrue()); + EXPECT_TRUE(x[2u].IsFalse()); + EXPECT_TRUE(x[3u].IsInt()); + EXPECT_EQ(123, x[3u].GetInt()); + EXPECT_TRUE(y[SizeType(0)].IsNull()); + EXPECT_TRUE(y[1u].IsTrue()); + EXPECT_TRUE(y[2u].IsFalse()); + EXPECT_TRUE(y[3u].IsInt()); + EXPECT_EQ(123, y[3u].GetInt()); + EXPECT_TRUE(y[4u].IsString()); + EXPECT_STREQ("foo", y[4u].GetString()); - // iterator - Value::ValueIterator itr = x.Begin(); - EXPECT_TRUE(itr != x.End()); - EXPECT_TRUE(itr->IsNull()); - ++itr; - EXPECT_TRUE(itr != x.End()); - EXPECT_TRUE(itr->IsTrue()); - ++itr; - EXPECT_TRUE(itr != x.End()); - EXPECT_TRUE(itr->IsFalse()); - ++itr; - EXPECT_TRUE(itr != x.End()); - EXPECT_TRUE(itr->IsInt()); - EXPECT_EQ(123, itr->GetInt()); - ++itr; - EXPECT_TRUE(itr != x.End()); - EXPECT_TRUE(itr->IsString()); - EXPECT_STREQ("foo", itr->GetString()); + // iterator + Value::ValueIterator itr = x.Begin(); + EXPECT_TRUE(itr != x.End()); + EXPECT_TRUE(itr->IsNull()); + ++itr; + EXPECT_TRUE(itr != x.End()); + EXPECT_TRUE(itr->IsTrue()); + ++itr; + EXPECT_TRUE(itr != x.End()); + EXPECT_TRUE(itr->IsFalse()); + ++itr; + EXPECT_TRUE(itr != x.End()); + EXPECT_TRUE(itr->IsInt()); + EXPECT_EQ(123, itr->GetInt()); + ++itr; + EXPECT_TRUE(itr != x.End()); + EXPECT_TRUE(itr->IsString()); + EXPECT_STREQ("foo", itr->GetString()); - // const iterator - Value::ConstValueIterator citr = y.Begin(); - EXPECT_TRUE(citr != y.End()); - EXPECT_TRUE(citr->IsNull()); - ++citr; - EXPECT_TRUE(citr != y.End()); - EXPECT_TRUE(citr->IsTrue()); - ++citr; - EXPECT_TRUE(citr != y.End()); - EXPECT_TRUE(citr->IsFalse()); - ++citr; - EXPECT_TRUE(citr != y.End()); - EXPECT_TRUE(citr->IsInt()); - EXPECT_EQ(123, citr->GetInt()); - ++citr; - EXPECT_TRUE(citr != y.End()); - EXPECT_TRUE(citr->IsString()); - EXPECT_STREQ("foo", citr->GetString()); + // const iterator + Value::ConstValueIterator citr = y.Begin(); + EXPECT_TRUE(citr != y.End()); + EXPECT_TRUE(citr->IsNull()); + ++citr; + EXPECT_TRUE(citr != y.End()); + EXPECT_TRUE(citr->IsTrue()); + ++citr; + EXPECT_TRUE(citr != y.End()); + EXPECT_TRUE(citr->IsFalse()); + ++citr; + EXPECT_TRUE(citr != y.End()); + EXPECT_TRUE(citr->IsInt()); + EXPECT_EQ(123, citr->GetInt()); + ++citr; + EXPECT_TRUE(citr != y.End()); + EXPECT_TRUE(citr->IsString()); + EXPECT_STREQ("foo", citr->GetString()); - // PopBack() - x.PopBack(); - EXPECT_EQ(4u, x.Size()); - EXPECT_TRUE(y[SizeType(0)].IsNull()); - EXPECT_TRUE(y[1u].IsTrue()); - EXPECT_TRUE(y[2u].IsFalse()); - EXPECT_TRUE(y[3u].IsInt()); + // PopBack() + x.PopBack(); + EXPECT_EQ(4u, x.Size()); + EXPECT_TRUE(y[SizeType(0)].IsNull()); + EXPECT_TRUE(y[1u].IsTrue()); + EXPECT_TRUE(y[2u].IsFalse()); + EXPECT_TRUE(y[3u].IsInt()); - // Clear() - x.Clear(); - EXPECT_TRUE(x.Empty()); - EXPECT_EQ(0u, x.Size()); - EXPECT_TRUE(y.Empty()); - EXPECT_EQ(0u, y.Size()); + // Clear() + x.Clear(); + EXPECT_TRUE(x.Empty()); + EXPECT_EQ(0u, x.Size()); + EXPECT_TRUE(y.Empty()); + EXPECT_EQ(0u, y.Size()); - // Erase(ValueIterator) + // Erase(ValueIterator) - // Use array of array to ensure removed elements' destructor is called. - // [[0],[1],[2],...] - for (int i = 0; i < 10; i++) - x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator); + // Use array of array to ensure removed elements' destructor is called. + // [[0],[1],[2],...] + for (int i = 0; i < 10; i++) + x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator); - // Erase the first - itr = x.Erase(x.Begin()); - EXPECT_EQ(x.Begin(), itr); - EXPECT_EQ(9u, x.Size()); - for (int i = 0; i < 9; i++) - EXPECT_EQ(i + 1, x[i][0u].GetInt()); + // Erase the first + itr = x.Erase(x.Begin()); + EXPECT_EQ(x.Begin(), itr); + EXPECT_EQ(9u, x.Size()); + for (int i = 0; i < 9; i++) + EXPECT_EQ(i + 1, x[i][0u].GetInt()); - // Ease the last - itr = x.Erase(x.End() - 1); - EXPECT_EQ(x.End(), itr); - EXPECT_EQ(8u, x.Size()); - for (int i = 0; i < 8; i++) - EXPECT_EQ(i + 1, x[i][0u].GetInt()); + // Ease the last + itr = x.Erase(x.End() - 1); + EXPECT_EQ(x.End(), itr); + EXPECT_EQ(8u, x.Size()); + for (int i = 0; i < 8; i++) + EXPECT_EQ(i + 1, x[i][0u].GetInt()); - // Erase the middle - itr = x.Erase(x.Begin() + 4); - EXPECT_EQ(x.Begin() + 4, itr); - EXPECT_EQ(7u, x.Size()); - for (int i = 0; i < 4; i++) - EXPECT_EQ(i + 1, x[i][0u].GetInt()); - for (int i = 4; i < 7; i++) - EXPECT_EQ(i + 2, x[i][0u].GetInt()); + // Erase the middle + itr = x.Erase(x.Begin() + 4); + EXPECT_EQ(x.Begin() + 4, itr); + EXPECT_EQ(7u, x.Size()); + for (int i = 0; i < 4; i++) + EXPECT_EQ(i + 1, x[i][0u].GetInt()); + for (int i = 4; i < 7; i++) + EXPECT_EQ(i + 2, x[i][0u].GetInt()); - // Erase(ValueIterator, ValueIterator) - // Exhaustive test with all 0 <= first < n, first <= last <= n cases - const unsigned n = 10; - for (unsigned first = 0; first < n; first++) { - for (unsigned last = first; last <= n; last++) { - x.Clear(); - for (unsigned i = 0; i < n; i++) - x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator); - - itr = x.Erase(x.Begin() + first, x.Begin() + last); - if (last == n) - EXPECT_EQ(x.End(), itr); - else - EXPECT_EQ(x.Begin() + first, itr); + // Erase(ValueIterator, ValueIterator) + // Exhaustive test with all 0 <= first < n, first <= last <= n cases + const unsigned n = 10; + for (unsigned first = 0; first < n; first++) { + for (unsigned last = first; last <= n; last++) { + x.Clear(); + for (unsigned i = 0; i < n; i++) + x.PushBack(Value(kArrayType).PushBack(i, allocator).Move(), allocator); + + itr = x.Erase(x.Begin() + first, x.Begin() + last); + if (last == n) + EXPECT_EQ(x.End(), itr); + else + EXPECT_EQ(x.Begin() + first, itr); - size_t removeCount = last - first; - EXPECT_EQ(n - removeCount, x.Size()); - for (unsigned i = 0; i < first; i++) - EXPECT_EQ(i, x[i][0u].GetUint()); - for (unsigned i = first; i < n - removeCount; i++) - EXPECT_EQ(i + removeCount, x[i][0u].GetUint()); - } - } + size_t removeCount = last - first; + EXPECT_EQ(n - removeCount, x.Size()); + for (unsigned i = 0; i < first; i++) + EXPECT_EQ(i, x[i][0u].GetUint()); + for (unsigned i = first; i < n - removeCount; i++) + EXPECT_EQ(i + removeCount, x[i][0u].GetUint()); + } + } - // Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed. + // Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed. #if 0 - // http://en.wikipedia.org/wiki/Erase-remove_idiom - x.Clear(); - for (int i = 0; i < 10; i++) - if (i % 2 == 0) - x.PushBack(i, allocator); - else - x.PushBack(Value(kNullType).Move(), allocator); + // http://en.wikipedia.org/wiki/Erase-remove_idiom + x.Clear(); + for (int i = 0; i < 10; i++) + if (i % 2 == 0) + x.PushBack(i, allocator); + else + x.PushBack(Value(kNullType).Move(), allocator); - x.Erase(std::remove(x.Begin(), x.End(), Value(kNullType)), x.End()); - EXPECT_EQ(5u, x.Size()); - for (int i = 0; i < 5; i++) - EXPECT_EQ(i * 2, x[i]); + x.Erase(std::remove(x.Begin(), x.End(), Value(kNullType)), x.End()); + EXPECT_EQ(5u, x.Size()); + for (int i = 0; i < 5; i++) + EXPECT_EQ(i * 2, x[i]); #endif - // SetArray() - Value z; - z.SetArray(); - EXPECT_TRUE(z.IsArray()); - EXPECT_TRUE(z.Empty()); + // SetArray() + Value z; + z.SetArray(); + EXPECT_TRUE(z.IsArray()); + EXPECT_TRUE(z.Empty()); } TEST(Value, Object) { - Value x(kObjectType); - const Value& y = x; // const version - Value::AllocatorType allocator; + Value x(kObjectType); + const Value& y = x; // const version + Value::AllocatorType allocator; - EXPECT_EQ(kObjectType, x.GetType()); - EXPECT_TRUE(x.IsObject()); - EXPECT_EQ(kObjectType, y.GetType()); - EXPECT_TRUE(y.IsObject()); + EXPECT_EQ(kObjectType, x.GetType()); + EXPECT_TRUE(x.IsObject()); + EXPECT_EQ(kObjectType, y.GetType()); + EXPECT_TRUE(y.IsObject()); - // AddMember() - x.AddMember("A", "Apple", allocator); + // AddMember() + x.AddMember("A", "Apple", allocator); - Value value("Banana", 6); - x.AddMember("B", "Banana", allocator); + Value value("Banana", 6); + x.AddMember("B", "Banana", allocator); - // AddMember(StringRefType, T, Allocator) - { - Value o(kObjectType); - o.AddMember("true", true, allocator); - o.AddMember("false", false, allocator); - o.AddMember("int", -1, allocator); - o.AddMember("uint", 1u, allocator); - o.AddMember("int64", INT64_C(-4294967296), allocator); - o.AddMember("uint64", UINT64_C(4294967296), allocator); - o.AddMember("double", 3.14, allocator); - o.AddMember("string", "Jelly", allocator); + // AddMember(StringRefType, T, Allocator) + { + Value o(kObjectType); + o.AddMember("true", true, allocator); + o.AddMember("false", false, allocator); + o.AddMember("int", -1, allocator); + o.AddMember("uint", 1u, allocator); + o.AddMember("int64", INT64_C(-4294967296), allocator); + o.AddMember("uint64", UINT64_C(4294967296), allocator); + o.AddMember("double", 3.14, allocator); + o.AddMember("string", "Jelly", allocator); - EXPECT_TRUE(o["true"].GetBool()); - EXPECT_FALSE(o["false"].GetBool()); - EXPECT_EQ(-1, o["int"].GetInt()); - EXPECT_EQ(1u, o["uint"].GetUint()); - EXPECT_EQ(INT64_C(-4294967296), o["int64"].GetInt64()); - EXPECT_EQ(UINT64_C(4294967296), o["uint64"].GetUint64()); - EXPECT_STREQ("Jelly",o["string"].GetString()); - } + EXPECT_TRUE(o["true"].GetBool()); + EXPECT_FALSE(o["false"].GetBool()); + EXPECT_EQ(-1, o["int"].GetInt()); + EXPECT_EQ(1u, o["uint"].GetUint()); + EXPECT_EQ(INT64_C(-4294967296), o["int64"].GetInt64()); + EXPECT_EQ(UINT64_C(4294967296), o["uint64"].GetUint64()); + EXPECT_STREQ("Jelly",o["string"].GetString()); + } - // Tests a member with null character - Value name; - const Value C0D("C\0D", 3); - name.SetString(C0D.GetString(), 3); - value.SetString("CherryD", 7); - x.AddMember(name, value, allocator); + // Tests a member with null character + Value name; + const Value C0D("C\0D", 3); + name.SetString(C0D.GetString(), 3); + value.SetString("CherryD", 7); + x.AddMember(name, value, allocator); - // HasMember() - EXPECT_TRUE(x.HasMember("A")); - EXPECT_TRUE(x.HasMember("B")); - EXPECT_TRUE(y.HasMember("A")); - EXPECT_TRUE(y.HasMember("B")); + // HasMember() + EXPECT_TRUE(x.HasMember("A")); + EXPECT_TRUE(x.HasMember("B")); + EXPECT_TRUE(y.HasMember("A")); + EXPECT_TRUE(y.HasMember("B")); - name.SetString("C\0D"); - EXPECT_TRUE(x.HasMember(name)); - EXPECT_TRUE(y.HasMember(name)); + name.SetString("C\0D"); + EXPECT_TRUE(x.HasMember(name)); + EXPECT_TRUE(y.HasMember(name)); - // operator[] - EXPECT_STREQ("Apple", x["A"].GetString()); - EXPECT_STREQ("Banana", x["B"].GetString()); - EXPECT_STREQ("CherryD", x[C0D].GetString()); + // operator[] + EXPECT_STREQ("Apple", x["A"].GetString()); + EXPECT_STREQ("Banana", x["B"].GetString()); + EXPECT_STREQ("CherryD", x[C0D].GetString()); - // const operator[] - EXPECT_STREQ("Apple", y["A"].GetString()); - EXPECT_STREQ("Banana", y["B"].GetString()); - EXPECT_STREQ("CherryD", y[C0D].GetString()); + // const operator[] + EXPECT_STREQ("Apple", y["A"].GetString()); + EXPECT_STREQ("Banana", y["B"].GetString()); + EXPECT_STREQ("CherryD", y[C0D].GetString()); - // member iterator - Value::MemberIterator itr = x.MemberBegin(); - EXPECT_TRUE(itr != x.MemberEnd()); - EXPECT_STREQ("A", itr->name.GetString()); - EXPECT_STREQ("Apple", itr->value.GetString()); - ++itr; - EXPECT_TRUE(itr != x.MemberEnd()); - EXPECT_STREQ("B", itr->name.GetString()); - EXPECT_STREQ("Banana", itr->value.GetString()); - ++itr; - EXPECT_TRUE(itr != x.MemberEnd()); - EXPECT_TRUE(memcmp(itr->name.GetString(), "C\0D", 4) == 0); - EXPECT_STREQ("CherryD", itr->value.GetString()); - ++itr; - EXPECT_FALSE(itr != x.MemberEnd()); + // member iterator + Value::MemberIterator itr = x.MemberBegin(); + EXPECT_TRUE(itr != x.MemberEnd()); + EXPECT_STREQ("A", itr->name.GetString()); + EXPECT_STREQ("Apple", itr->value.GetString()); + ++itr; + EXPECT_TRUE(itr != x.MemberEnd()); + EXPECT_STREQ("B", itr->name.GetString()); + EXPECT_STREQ("Banana", itr->value.GetString()); + ++itr; + EXPECT_TRUE(itr != x.MemberEnd()); + EXPECT_TRUE(memcmp(itr->name.GetString(), "C\0D", 4) == 0); + EXPECT_STREQ("CherryD", itr->value.GetString()); + ++itr; + EXPECT_FALSE(itr != x.MemberEnd()); - // const member iterator - Value::ConstMemberIterator citr = y.MemberBegin(); - EXPECT_TRUE(citr != y.MemberEnd()); - EXPECT_STREQ("A", citr->name.GetString()); - EXPECT_STREQ("Apple", citr->value.GetString()); - ++citr; - EXPECT_TRUE(citr != y.MemberEnd()); - EXPECT_STREQ("B", citr->name.GetString()); - EXPECT_STREQ("Banana", citr->value.GetString()); - ++citr; - EXPECT_TRUE(citr != y.MemberEnd()); - EXPECT_TRUE(memcmp(citr->name.GetString(), "C\0D", 4) == 0); - EXPECT_STREQ("CherryD", citr->value.GetString()); - ++citr; - EXPECT_FALSE(citr != y.MemberEnd()); + // const member iterator + Value::ConstMemberIterator citr = y.MemberBegin(); + EXPECT_TRUE(citr != y.MemberEnd()); + EXPECT_STREQ("A", citr->name.GetString()); + EXPECT_STREQ("Apple", citr->value.GetString()); + ++citr; + EXPECT_TRUE(citr != y.MemberEnd()); + EXPECT_STREQ("B", citr->name.GetString()); + EXPECT_STREQ("Banana", citr->value.GetString()); + ++citr; + EXPECT_TRUE(citr != y.MemberEnd()); + EXPECT_TRUE(memcmp(citr->name.GetString(), "C\0D", 4) == 0); + EXPECT_STREQ("CherryD", citr->value.GetString()); + ++citr; + EXPECT_FALSE(citr != y.MemberEnd()); - // RemoveMember() - x.RemoveMember("A"); - EXPECT_FALSE(x.HasMember("A")); + // RemoveMember() + x.RemoveMember("A"); + EXPECT_FALSE(x.HasMember("A")); - x.RemoveMember("B"); - EXPECT_FALSE(x.HasMember("B")); + x.RemoveMember("B"); + EXPECT_FALSE(x.HasMember("B")); - x.RemoveMember(name); - EXPECT_FALSE(x.HasMember(name)); + x.RemoveMember(name); + EXPECT_FALSE(x.HasMember(name)); - EXPECT_TRUE(x.MemberBegin() == x.MemberEnd()); + EXPECT_TRUE(x.MemberBegin() == x.MemberEnd()); - // EraseMember(ConstMemberIterator) + // EraseMember(ConstMemberIterator) - // Use array members to ensure removed elements' destructor is called. - // { "a": [0], "b": [1],[2],...] - const char keys[][2] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; - for (int i = 0; i < 10; i++) - x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); + // Use array members to ensure removed elements' destructor is called. + // { "a": [0], "b": [1],[2],...] + const char keys[][2] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" }; + for (int i = 0; i < 10; i++) + x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); - // Erase the first - itr = x.EraseMember(x.MemberBegin()); - EXPECT_FALSE(x.HasMember(keys[0])); - EXPECT_EQ(x.MemberBegin(), itr); - EXPECT_EQ(9u, x.MemberEnd() - x.MemberBegin()); - for (; itr != x.MemberEnd(); ++itr) { - int i = (itr - x.MemberBegin()) + 1; - EXPECT_STREQ(itr->name.GetString(), keys[i]); - EXPECT_EQ(i, itr->value[0u].GetInt()); - } + // Erase the first + itr = x.EraseMember(x.MemberBegin()); + EXPECT_FALSE(x.HasMember(keys[0])); + EXPECT_EQ(x.MemberBegin(), itr); + EXPECT_EQ(9u, x.MemberEnd() - x.MemberBegin()); + for (; itr != x.MemberEnd(); ++itr) { + int i = (itr - x.MemberBegin()) + 1; + EXPECT_STREQ(itr->name.GetString(), keys[i]); + EXPECT_EQ(i, itr->value[0u].GetInt()); + } - // Erase the last - itr = x.EraseMember(x.MemberEnd() - 1); - EXPECT_FALSE(x.HasMember(keys[9])); - EXPECT_EQ(x.MemberEnd(), itr); - EXPECT_EQ(8u, x.MemberEnd() - x.MemberBegin()); - for (; itr != x.MemberEnd(); ++itr) { - int i = (itr - x.MemberBegin()) + 1; - EXPECT_STREQ(itr->name.GetString(), keys[i]); - EXPECT_EQ(i, itr->value[0u].GetInt()); - } + // Erase the last + itr = x.EraseMember(x.MemberEnd() - 1); + EXPECT_FALSE(x.HasMember(keys[9])); + EXPECT_EQ(x.MemberEnd(), itr); + EXPECT_EQ(8u, x.MemberEnd() - x.MemberBegin()); + for (; itr != x.MemberEnd(); ++itr) { + int i = (itr - x.MemberBegin()) + 1; + EXPECT_STREQ(itr->name.GetString(), keys[i]); + EXPECT_EQ(i, itr->value[0u].GetInt()); + } - // Erase the middle - itr = x.EraseMember(x.MemberBegin() + 4); - EXPECT_FALSE(x.HasMember(keys[5])); - EXPECT_EQ(x.MemberBegin() + 4, itr); - EXPECT_EQ(7u, x.MemberEnd() - x.MemberBegin()); - for (; itr != x.MemberEnd(); ++itr) { - int i = (itr - x.MemberBegin()); - i += (i<4) ? 1 : 2; - EXPECT_STREQ(itr->name.GetString(), keys[i]); - EXPECT_EQ(i, itr->value[0u].GetInt()); - } + // Erase the middle + itr = x.EraseMember(x.MemberBegin() + 4); + EXPECT_FALSE(x.HasMember(keys[5])); + EXPECT_EQ(x.MemberBegin() + 4, itr); + EXPECT_EQ(7u, x.MemberEnd() - x.MemberBegin()); + for (; itr != x.MemberEnd(); ++itr) { + int i = (itr - x.MemberBegin()); + i += (i<4) ? 1 : 2; + EXPECT_STREQ(itr->name.GetString(), keys[i]); + EXPECT_EQ(i, itr->value[0u].GetInt()); + } - // EraseMember(ConstMemberIterator, ConstMemberIterator) - // Exhaustive test with all 0 <= first < n, first <= last <= n cases - const unsigned n = 10; - for (unsigned first = 0; first < n; first++) { - for (unsigned last = first; last <= n; last++) { - Value(kObjectType).Swap(x); - for (unsigned i = 0; i < n; i++) - x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); + // EraseMember(ConstMemberIterator, ConstMemberIterator) + // Exhaustive test with all 0 <= first < n, first <= last <= n cases + const unsigned n = 10; + for (unsigned first = 0; first < n; first++) { + for (unsigned last = first; last <= n; last++) { + Value(kObjectType).Swap(x); + for (unsigned i = 0; i < n; i++) + x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator); - itr = x.EraseMember(x.MemberBegin() + first, x.MemberBegin() + last); - if (last == n) - EXPECT_EQ(x.MemberEnd(), itr); - else - EXPECT_EQ(x.MemberBegin() + first, itr); + itr = x.EraseMember(x.MemberBegin() + first, x.MemberBegin() + last); + if (last == n) + EXPECT_EQ(x.MemberEnd(), itr); + else + EXPECT_EQ(x.MemberBegin() + first, itr); - size_t removeCount = last - first; - EXPECT_EQ(n - removeCount, size_t(x.MemberEnd() - x.MemberBegin())); - for (unsigned i = 0; i < first; i++) - EXPECT_EQ(i, x[keys[i]][0u].GetUint()); - for (unsigned i = first; i < n - removeCount; i++) - EXPECT_EQ(i + removeCount, x[keys[i+removeCount]][0u].GetUint()); - } - } + size_t removeCount = last - first; + EXPECT_EQ(n - removeCount, size_t(x.MemberEnd() - x.MemberBegin())); + for (unsigned i = 0; i < first; i++) + EXPECT_EQ(i, x[keys[i]][0u].GetUint()); + for (unsigned i = first; i < n - removeCount; i++) + EXPECT_EQ(i + removeCount, x[keys[i+removeCount]][0u].GetUint()); + } + } - // SetObject() - Value z; - z.SetObject(); - EXPECT_TRUE(z.IsObject()); + // SetObject() + Value z; + z.SetObject(); + EXPECT_TRUE(z.IsObject()); } TEST(Value, BigNestedArray) { - MemoryPoolAllocator<> allocator; - Value x(kArrayType); - static const SizeType n = 200; + MemoryPoolAllocator<> allocator; + Value x(kArrayType); + static const SizeType n = 200; - for (SizeType i = 0; i < n; i++) { - Value y(kArrayType); - for (SizeType j = 0; j < n; j++) { - Value number((int)(i * n + j)); - y.PushBack(number, allocator); - } - x.PushBack(y, allocator); - } + for (SizeType i = 0; i < n; i++) { + Value y(kArrayType); + for (SizeType j = 0; j < n; j++) { + Value number((int)(i * n + j)); + y.PushBack(number, allocator); + } + x.PushBack(y, allocator); + } - for (SizeType i = 0; i < n; i++) - for (SizeType j = 0; j < n; j++) { - EXPECT_TRUE(x[i][j].IsInt()); - EXPECT_EQ((int)(i * n + j), x[i][j].GetInt()); - } + for (SizeType i = 0; i < n; i++) + for (SizeType j = 0; j < n; j++) { + EXPECT_TRUE(x[i][j].IsInt()); + EXPECT_EQ((int)(i * n + j), x[i][j].GetInt()); + } } TEST(Value, BigNestedObject) { - MemoryPoolAllocator<> allocator; - Value x(kObjectType); - static const SizeType n = 200; + MemoryPoolAllocator<> allocator; + Value x(kObjectType); + static const SizeType n = 200; - for (SizeType i = 0; i < n; i++) { - char name1[10]; - sprintf(name1, "%d", i); + for (SizeType i = 0; i < n; i++) { + char name1[10]; + sprintf(name1, "%d", i); - // Value name(name1); // should not compile - Value name(name1, (SizeType)strlen(name1), allocator); - Value object(kObjectType); + // Value name(name1); // should not compile + Value name(name1, (SizeType)strlen(name1), allocator); + Value object(kObjectType); - for (SizeType j = 0; j < n; j++) { - char name2[10]; - sprintf(name2, "%d", j); + for (SizeType j = 0; j < n; j++) { + char name2[10]; + sprintf(name2, "%d", j); - Value name(name2, (SizeType)strlen(name2), allocator); - Value number((int)(i * n + j)); - object.AddMember(name, number, allocator); - } + Value name(name2, (SizeType)strlen(name2), allocator); + Value number((int)(i * n + j)); + object.AddMember(name, number, allocator); + } - // x.AddMember(name1, object, allocator); // should not compile - x.AddMember(name, object, allocator); - } + // x.AddMember(name1, object, allocator); // should not compile + x.AddMember(name, object, allocator); + } - for (SizeType i = 0; i < n; i++) { - char name1[10]; - sprintf(name1, "%d", i); - - for (SizeType j = 0; j < n; j++) { - char name2[10]; - sprintf(name2, "%d", j); - x[name1]; - EXPECT_EQ((int)(i * n + j), x[name1][name2].GetInt()); - } - } + for (SizeType i = 0; i < n; i++) { + char name1[10]; + sprintf(name1, "%d", i); + + for (SizeType j = 0; j < n; j++) { + char name2[10]; + sprintf(name2, "%d", j); + x[name1]; + EXPECT_EQ((int)(i * n + j), x[name1][name2].GetInt()); + } + } } // Issue 18: Error removing last element of object // http://code.google.com/p/rapidjson/issues/detail?id=18 TEST(Value, RemoveLastElement) { - rapidjson::Document doc; - rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); - rapidjson::Value objVal(rapidjson::kObjectType); - objVal.AddMember("var1", 123, allocator); - objVal.AddMember("var2", "444", allocator); - objVal.AddMember("var3", 555, allocator); - EXPECT_TRUE(objVal.HasMember("var3")); - objVal.RemoveMember("var3"); // Assertion here in r61 - EXPECT_FALSE(objVal.HasMember("var3")); + rapidjson::Document doc; + rapidjson::Document::AllocatorType& allocator = doc.GetAllocator(); + rapidjson::Value objVal(rapidjson::kObjectType); + objVal.AddMember("var1", 123, allocator); + objVal.AddMember("var2", "444", allocator); + objVal.AddMember("var3", 555, allocator); + EXPECT_TRUE(objVal.HasMember("var3")); + objVal.RemoveMember("var3"); // Assertion here in r61 + EXPECT_FALSE(objVal.HasMember("var3")); } -// Issue 38: Segmentation fault with CrtAllocator +// Issue 38: Segmentation fault with CrtAllocator TEST(Document, CrtAllocator) { - typedef GenericValue, CrtAllocator> V; + typedef GenericValue, CrtAllocator> V; - V::AllocatorType allocator; - V o(kObjectType); - o.AddMember("x", 1, allocator); // Should not call destructor on uninitialized name/value of newly allocated members. + V::AllocatorType allocator; + V o(kObjectType); + o.AddMember("x", 1, allocator); // Should not call destructor on uninitialized name/value of newly allocated members. - V a(kArrayType); - a.PushBack(1, allocator); // Should not call destructor on uninitialized Value of newly allocated elements. + V a(kArrayType); + a.PushBack(1, allocator); // Should not call destructor on uninitialized Value of newly allocated elements. } diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 59543b0..2d83418 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -1,3 +1,23 @@ +// Copyright (C) 2011 Milo Yip +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + #include "unittest.h" #include "rapidjson/document.h" @@ -8,235 +28,235 @@ using namespace rapidjson; TEST(Writer, Compact) { - StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "); - StringBuffer buffer; - Writer writer(buffer); - Reader reader; - reader.Parse<0>(s, writer); - EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", buffer.GetString()); - EXPECT_EQ(77u, buffer.GetSize()); - EXPECT_TRUE(writer.IsComplete()); + StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "); + StringBuffer buffer; + Writer writer(buffer); + Reader reader; + reader.Parse<0>(s, writer); + EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", buffer.GetString()); + EXPECT_EQ(77u, buffer.GetSize()); + EXPECT_TRUE(writer.IsComplete()); } // json -> parse -> writer -> json #define TEST_ROUNDTRIP(json) \ - { \ - StringStream s(json); \ - StringBuffer buffer; \ - Writer writer(buffer); \ - Reader reader; \ - reader.Parse<0>(s, writer); \ - EXPECT_STREQ(json, buffer.GetString()); \ - EXPECT_TRUE(writer.IsComplete()); \ - } + { \ + StringStream s(json); \ + StringBuffer buffer; \ + Writer writer(buffer); \ + Reader reader; \ + reader.Parse<0>(s, writer); \ + EXPECT_STREQ(json, buffer.GetString()); \ + EXPECT_TRUE(writer.IsComplete()); \ + } TEST(Writer, Int) { - TEST_ROUNDTRIP("[-1]"); - TEST_ROUNDTRIP("[-123]"); - TEST_ROUNDTRIP("[-2147483648]"); + TEST_ROUNDTRIP("[-1]"); + TEST_ROUNDTRIP("[-123]"); + TEST_ROUNDTRIP("[-2147483648]"); } TEST(Writer, UInt) { - TEST_ROUNDTRIP("[0]"); - TEST_ROUNDTRIP("[1]"); - TEST_ROUNDTRIP("[123]"); - TEST_ROUNDTRIP("[2147483647]"); - TEST_ROUNDTRIP("[4294967295]"); + TEST_ROUNDTRIP("[0]"); + TEST_ROUNDTRIP("[1]"); + TEST_ROUNDTRIP("[123]"); + TEST_ROUNDTRIP("[2147483647]"); + TEST_ROUNDTRIP("[4294967295]"); } TEST(Writer, Int64) { - TEST_ROUNDTRIP("[-1234567890123456789]"); - TEST_ROUNDTRIP("[-9223372036854775808]"); + TEST_ROUNDTRIP("[-1234567890123456789]"); + TEST_ROUNDTRIP("[-9223372036854775808]"); } TEST(Writer, Uint64) { - TEST_ROUNDTRIP("[1234567890123456789]"); - TEST_ROUNDTRIP("[9223372036854775807]"); + TEST_ROUNDTRIP("[1234567890123456789]"); + TEST_ROUNDTRIP("[9223372036854775807]"); } TEST(Writer, String) { - TEST_ROUNDTRIP("[\"Hello\"]"); - TEST_ROUNDTRIP("[\"Hello\\u0000World\"]"); - TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]"); + TEST_ROUNDTRIP("[\"Hello\"]"); + TEST_ROUNDTRIP("[\"Hello\\u0000World\"]"); + TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]"); } TEST(Writer, Double) { - TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]"); + TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]"); } TEST(Writer, Transcode) { - const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}"; + const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}"; - // UTF8 -> UTF16 -> UTF8 - { - StringStream s(json); - StringBuffer buffer; - Writer, UTF8<> > writer(buffer); - GenericReader, UTF16<> > reader; - reader.Parse(s, writer); - EXPECT_STREQ(json, buffer.GetString()); - } + // UTF8 -> UTF16 -> UTF8 + { + StringStream s(json); + StringBuffer buffer; + Writer, UTF8<> > writer(buffer); + GenericReader, UTF16<> > reader; + reader.Parse(s, writer); + EXPECT_STREQ(json, buffer.GetString()); + } - // UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8 - { - StringStream s(json); - StringBuffer buffer; - Writer, ASCII<> > writer(buffer); - Reader reader; - reader.Parse(s, writer); + // UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8 + { + StringStream s(json); + StringBuffer buffer; + Writer, ASCII<> > writer(buffer); + Reader reader; + reader.Parse(s, writer); - StringBuffer buffer2; - Writer writer2(buffer2); - GenericReader, UTF8<> > reader2; - StringStream s2(buffer.GetString()); - reader2.Parse(s2, writer2); + StringBuffer buffer2; + Writer writer2(buffer2); + GenericReader, UTF8<> > reader2; + StringStream s2(buffer.GetString()); + reader2.Parse(s2, writer2); - EXPECT_STREQ(json, buffer2.GetString()); - } + EXPECT_STREQ(json, buffer2.GetString()); + } } #include class OStreamWrapper { public: - typedef char Ch; + typedef char Ch; - OStreamWrapper(std::ostream& os) : os_(os) {} + OStreamWrapper(std::ostream& os) : os_(os) {} - Ch Peek() const { assert(false); return '\0'; } - Ch Take() { assert(false); return '\0'; } - size_t Tell() const { return 0; } + Ch Peek() const { assert(false); return '\0'; } + Ch Take() { assert(false); return '\0'; } + size_t Tell() const { return 0; } - Ch* PutBegin() { assert(false); return 0; } - void Put(Ch c) { os_.put(c); } - void Flush() { os_.flush(); } - size_t PutEnd(Ch*) { assert(false); return 0; } + Ch* PutBegin() { assert(false); return 0; } + void Put(Ch c) { os_.put(c); } + void Flush() { os_.flush(); } + size_t PutEnd(Ch*) { assert(false); return 0; } private: - OStreamWrapper(const OStreamWrapper&); - OStreamWrapper& operator=(const OStreamWrapper&); + OStreamWrapper(const OStreamWrapper&); + OStreamWrapper& operator=(const OStreamWrapper&); - std::ostream& os_; + std::ostream& os_; }; TEST(Writer, OStreamWrapper) { - StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "); - - std::stringstream ss; - OStreamWrapper os(ss); - - Writer writer(os); + StringStream s("{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "); + + std::stringstream ss; + OStreamWrapper os(ss); + + Writer writer(os); - Reader reader; - reader.Parse<0>(s, writer); - - std::string actual = ss.str(); - EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", actual.c_str()); + Reader reader; + reader.Parse<0>(s, writer); + + std::string actual = ss.str(); + EXPECT_STREQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3]}", actual.c_str()); } TEST(Writer, AssertRootMustBeArrayOrObject) { #define T(x)\ - {\ - StringBuffer buffer;\ - Writer writer(buffer);\ - ASSERT_THROW(x, AssertException);\ - } - T(writer.Bool(false)); - T(writer.Bool(true)); - T(writer.Null()); - T(writer.Int(0)); - T(writer.Uint(0)); - T(writer.Int64(0)); - T(writer.Uint64(0)); - T(writer.Double(0)); - T(writer.String("foo")); + {\ + StringBuffer buffer;\ + Writer writer(buffer);\ + ASSERT_THROW(x, AssertException);\ + } + T(writer.Bool(false)); + T(writer.Bool(true)); + T(writer.Null()); + T(writer.Int(0)); + T(writer.Uint(0)); + T(writer.Int64(0)); + T(writer.Uint64(0)); + T(writer.Double(0)); + T(writer.String("foo")); #undef T } TEST(Writer, AssertIncorrectObjectLevel) { - StringBuffer buffer; - Writer writer(buffer); - writer.StartObject(); - writer.EndObject(); - ASSERT_THROW(writer.EndObject(), AssertException); + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + writer.EndObject(); + ASSERT_THROW(writer.EndObject(), AssertException); } TEST(Writer, AssertIncorrectArrayLevel) { - StringBuffer buffer; - Writer writer(buffer); - writer.StartArray(); - writer.EndArray(); - ASSERT_THROW(writer.EndArray(), AssertException); + StringBuffer buffer; + Writer writer(buffer); + writer.StartArray(); + writer.EndArray(); + ASSERT_THROW(writer.EndArray(), AssertException); } TEST(Writer, AssertIncorrectEndObject) { - StringBuffer buffer; - Writer writer(buffer); - writer.StartObject(); - ASSERT_THROW(writer.EndArray(), AssertException); + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + ASSERT_THROW(writer.EndArray(), AssertException); } TEST(Writer, AssertIncorrectEndArray) { - StringBuffer buffer; - Writer writer(buffer); - writer.StartObject(); - ASSERT_THROW(writer.EndArray(), AssertException); + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + ASSERT_THROW(writer.EndArray(), AssertException); } TEST(Writer, AssertObjectKeyNotString) { #define T(x)\ - {\ - StringBuffer buffer;\ - Writer writer(buffer);\ - writer.StartObject();\ - ASSERT_THROW(x, AssertException); \ - } - T(writer.Bool(false)); - T(writer.Bool(true)); - T(writer.Null()); - T(writer.Int(0)); - T(writer.Uint(0)); - T(writer.Int64(0)); - T(writer.Uint64(0)); - T(writer.Double(0)); - T(writer.StartObject()); - T(writer.StartArray()); + {\ + StringBuffer buffer;\ + Writer writer(buffer);\ + writer.StartObject();\ + ASSERT_THROW(x, AssertException); \ + } + T(writer.Bool(false)); + T(writer.Bool(true)); + T(writer.Null()); + T(writer.Int(0)); + T(writer.Uint(0)); + T(writer.Int64(0)); + T(writer.Uint64(0)); + T(writer.Double(0)); + T(writer.StartObject()); + T(writer.StartArray()); #undef T } TEST(Writer, AssertMultipleRoot) { - StringBuffer buffer; - Writer writer(buffer); - writer.StartObject(); - writer.EndObject(); - ASSERT_THROW(writer.StartObject(), AssertException); + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + writer.EndObject(); + ASSERT_THROW(writer.StartObject(), AssertException); } TEST(Writer, RootObjectIsComplete) { - StringBuffer buffer; - Writer writer(buffer); - EXPECT_FALSE(writer.IsComplete()); - writer.StartObject(); - EXPECT_FALSE(writer.IsComplete()); - writer.String("foo"); - EXPECT_FALSE(writer.IsComplete()); - writer.Int(1); - EXPECT_FALSE(writer.IsComplete()); - writer.EndObject(); - EXPECT_TRUE(writer.IsComplete()); + StringBuffer buffer; + Writer writer(buffer); + EXPECT_FALSE(writer.IsComplete()); + writer.StartObject(); + EXPECT_FALSE(writer.IsComplete()); + writer.String("foo"); + EXPECT_FALSE(writer.IsComplete()); + writer.Int(1); + EXPECT_FALSE(writer.IsComplete()); + writer.EndObject(); + EXPECT_TRUE(writer.IsComplete()); } TEST(Writer, RootArrayIsComplete) { - StringBuffer buffer; - Writer writer(buffer); - EXPECT_FALSE(writer.IsComplete()); - writer.StartArray(); - EXPECT_FALSE(writer.IsComplete()); - writer.String("foo"); - EXPECT_FALSE(writer.IsComplete()); - writer.Int(1); - EXPECT_FALSE(writer.IsComplete()); - writer.EndArray(); - EXPECT_TRUE(writer.IsComplete()); + StringBuffer buffer; + Writer writer(buffer); + EXPECT_FALSE(writer.IsComplete()); + writer.StartArray(); + EXPECT_FALSE(writer.IsComplete()); + writer.String("foo"); + EXPECT_FALSE(writer.IsComplete()); + writer.Int(1); + EXPECT_FALSE(writer.IsComplete()); + writer.EndArray(); + EXPECT_TRUE(writer.IsComplete()); }