Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/miloyip/rapidjson.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilo Yip <miloyip@gmail.com>2014-08-11 18:26:45 +0400
committerMilo Yip <miloyip@gmail.com>2014-08-11 18:26:45 +0400
commit0dbcc1cf2ea62a40adf2f713bdb21685d85653ed (patch)
tree1165cb491d656e5d5220da184ff432bacb50d3fa
parentadb3974e4d078e253a31f4e9e034583bf41298d8 (diff)
Add license and change indents from tab to space.
-rw-r--r--build/premake4.lua312
-rw-r--r--example/capitalize/capitalize.cpp74
-rw-r--r--example/condense/condense.cpp28
-rw-r--r--example/messagereader/messagereader.cpp70
-rw-r--r--example/pretty/pretty.cpp28
-rw-r--r--example/prettyauto/prettyauto.cpp56
-rw-r--r--example/serialize/serialize.cpp162
-rw-r--r--example/simpledom/simpledom.cpp28
-rw-r--r--example/simplereader/simplereader.cpp32
-rw-r--r--example/simplewriter/simplewriter.cpp2
-rw-r--r--example/tutorial/tutorial.cpp280
-rw-r--r--include/rapidjson/allocators.h360
-rw-r--r--include/rapidjson/document.h2936
-rw-r--r--include/rapidjson/encodedstream.h412
-rw-r--r--include/rapidjson/encodings.h956
-rw-r--r--include/rapidjson/error/en.h90
-rw-r--r--include/rapidjson/error/error.h134
-rw-r--r--include/rapidjson/filereadstream.h116
-rw-r--r--include/rapidjson/filestream.h82
-rw-r--r--include/rapidjson/filewritestream.h124
-rw-r--r--include/rapidjson/internal/dtoa.h685
-rw-r--r--include/rapidjson/internal/itoa.h45
-rw-r--r--include/rapidjson/internal/meta.h38
-rw-r--r--include/rapidjson/internal/pow10.h66
-rw-r--r--include/rapidjson/internal/stack.h162
-rw-r--r--include/rapidjson/internal/strfunc.h34
-rw-r--r--include/rapidjson/memorybuffer.h62
-rw-r--r--include/rapidjson/memorystream.h68
-rw-r--r--include/rapidjson/prettywriter.h326
-rw-r--r--include/rapidjson/rapidjson.h224
-rw-r--r--include/rapidjson/reader.h2244
-rw-r--r--include/rapidjson/stringbuffer.h60
-rw-r--r--include/rapidjson/writer.h624
-rw-r--r--test/perftest/jsoncpptest.cpp76
-rw-r--r--test/perftest/misctest.cpp1550
-rw-r--r--test/perftest/perftest.cpp28
-rw-r--r--test/perftest/perftest.h120
-rw-r--r--test/perftest/platformtest.cpp188
-rw-r--r--test/perftest/rapidjsontest.cpp396
-rw-r--r--test/perftest/ultrajsontest.cpp92
-rw-r--r--test/perftest/yajltest.cpp290
-rw-r--r--test/unittest/documenttest.cpp316
-rw-r--r--test/unittest/encodedstreamtest.cpp480
-rw-r--r--test/unittest/encodingstest.cpp732
-rw-r--r--test/unittest/filestreamtest.cpp156
-rw-r--r--test/unittest/jsoncheckertest.cpp126
-rw-r--r--test/unittest/readertest.cpp1454
-rw-r--r--test/unittest/unittest.cpp28
-rw-r--r--test/unittest/unittest.h58
-rw-r--r--test/unittest/valuetest.cpp1770
-rw-r--r--test/unittest/writertest.cpp340
51 files changed, 9951 insertions, 9169 deletions
diff --git a/build/premake4.lua b/build/premake4.lua
index 822804c3..ba071311 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)
-
- 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
+ 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
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" }
-
- location ("./" .. (_ACTION or ""))
- language "C++"
- flags { "ExtraWarnings" }
-
- configuration "debug"
- defines { "DEBUG" }
- flags { "Symbols" }
-
- configuration "release"
- defines { "NDEBUG" }
- flags { "Optimize" }
-
- configuration "vs*"
- defines { "_CRT_SECURE_NO_WARNINGS" }
-
- configuration "gmake"
- buildoptions "-msse4.2 -Wall -Wextra"
-
- project "gtest"
- kind "StaticLib"
-
- defines { "GTEST_HAS_PTHREAD=0" }
-
- files {
- "../thirdparty/gtest/src/gtest-all.cc",
- "../thirdparty/gtest/src/**.h",
- }
-
- includedirs {
- "../thirdparty/gtest/",
- "../thirdparty/gtest/include",
- }
-
- setTargetObjDir("../thirdparty/lib")
-
- 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/",
- }
-
- libdirs "../thirdparty/lib"
-
- 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/",
- }
-
- libdirs "../thirdparty/lib"
-
- setTargetObjDir("../bin")
-
- linkLib "gtest"
- links "gtest"
+ configurations { "debug", "release" }
+ platforms { "x32", "x64" }
+
+ location ("./" .. (_ACTION or ""))
+ language "C++"
+ flags { "ExtraWarnings" }
+
+ configuration "debug"
+ defines { "DEBUG" }
+ flags { "Symbols" }
+
+ configuration "release"
+ defines { "NDEBUG" }
+ flags { "Optimize" }
+
+ configuration "vs*"
+ defines { "_CRT_SECURE_NO_WARNINGS" }
+
+ configuration "gmake"
+ buildoptions "-msse4.2 -Wall -Wextra"
+
+ project "gtest"
+ kind "StaticLib"
+
+ defines { "GTEST_HAS_PTHREAD=0" }
+
+ files {
+ "../thirdparty/gtest/src/gtest-all.cc",
+ "../thirdparty/gtest/src/**.h",
+ }
+
+ includedirs {
+ "../thirdparty/gtest/",
+ "../thirdparty/gtest/include",
+ }
+
+ setTargetObjDir("../thirdparty/lib")
+
+ 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/",
+ }
+
+ libdirs "../thirdparty/lib"
+
+ 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/",
+ }
+
+ libdirs "../thirdparty/lib"
+
+ setTargetObjDir("../bin")
+
+ linkLib "gtest"
+ links "gtest"
solution "example"
- configurations { "debug", "release" }
- platforms { "x32", "x64" }
- location ("./" .. (_ACTION or ""))
- language "C++"
- flags { "ExtraWarnings" }
- includedirs "../include/"
-
- configuration "debug"
- defines { "DEBUG" }
- flags { "Symbols" }
-
- configuration "release"
- defines { "NDEBUG" }
- flags { "Optimize", "EnableSSE2" }
-
- configuration "vs*"
- defines { "_CRT_SECURE_NO_WARNINGS" }
-
- 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
+ configurations { "debug", "release" }
+ platforms { "x32", "x64" }
+ location ("./" .. (_ACTION or ""))
+ language "C++"
+ flags { "ExtraWarnings" }
+ includedirs "../include/"
+
+ configuration "debug"
+ defines { "DEBUG" }
+ flags { "Symbols" }
+
+ configuration "release"
+ defines { "NDEBUG" }
+ flags { "Optimize", "EnableSSE2" }
+
+ configuration "vs*"
+ defines { "_CRT_SECURE_NO_WARNINGS" }
+
+ 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
diff --git a/example/capitalize/capitalize.cpp b/example/capitalize/capitalize.cpp
index 69b07d8f..b8d60860 100644
--- a/example/capitalize/capitalize.cpp
+++ b/example/capitalize/capitalize.cpp
@@ -15,51 +15,51 @@ using namespace rapidjson;
template<typename OutputHandler>
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<char> buffer_;
+ OutputHandler& out_;
+ std::vector<char> 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<FileWriteStream> writer(os);
+ // Prepare JSON writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ Writer<FileWriteStream> writer(os);
- // JSON reader parse from the input stream and let writer generate the output.
- CapitalizeFilter<Writer<FileWriteStream> > 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<Writer<FileWriteStream> > 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 bad3c91f..05e2007c 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<FileWriteStream> writer(os);
+ // Prepare JSON writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ Writer<FileWriteStream> 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 f5317c22..cf6f1e12 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 cfb3f0fd..164e3880 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<FileWriteStream> writer(os);
+ // Prepare writer and output stream.
+ char writeBuffer[65536];
+ FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
+ PrettyWriter<FileWriteStream> writer(os);
- // JSON reader parse from the input stream and let writer generate the output.
- if (!reader.Parse<kParseValidateEncodingFlag>(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<kParseValidateEncodingFlag>(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 3f85f405..0d309686 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 <fcntl.h>
@@ -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<AutoUTF<unsigned>, UTF8<> > reader; // CHANGED
- char readBuffer[65536];
- FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
- AutoUTFInputStream<unsigned, FileReadStream> eis(is); // NEW
+ // Prepare reader and input stream.
+ //Reader reader;
+ GenericReader<AutoUTF<unsigned>, UTF8<> > reader; // CHANGED
+ char readBuffer[65536];
+ FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
+ AutoUTFInputStream<unsigned, FileReadStream> 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<unsigned, FileWriteStream> OutputStream; // NEW
- OutputStream eos(os, eis.GetType(), eis.HasBOM()); // NEW
- PrettyWriter<OutputStream, UTF8<>, AutoUTF<unsigned> > writer(eos); // CHANGED
+ // Use the same Encoding of the input. Also use BOM according to input.
+ typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream; // NEW
+ OutputStream eos(os, eis.GetType(), eis.HasBOM()); // NEW
+ PrettyWriter<OutputStream, UTF8<>, AutoUTF<unsigned> > writer(eos); // CHANGED
#else
- // You may also use static bound encoding type, such as output to UTF-16LE with BOM
- typedef EncodedOutputStream<UTF16LE<>,FileWriteStream> OutputStream; // NEW
- OutputStream eos(os, true); // NEW
- PrettyWriter<OutputStream, UTF8<>, UTF16LE<> > writer(eos); // CHANGED
+ // You may also use static bound encoding type, such as output to UTF-16LE with BOM
+ typedef EncodedOutputStream<UTF16LE<>,FileWriteStream> OutputStream; // NEW
+ OutputStream eos(os, true); // NEW
+ PrettyWriter<OutputStream, UTF8<>, UTF16LE<> > writer(eos); // CHANGED
#endif
- // JSON reader parse from the input stream and let writer generate the output.
- //if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
- if (!reader.Parse<kParseValidateEncodingFlag>(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<kParseValidateEncodingFlag>(is, writer)) {
+ if (!reader.Parse<kParseValidateEncodingFlag>(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 6dfe2d48..68a54efc 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 <cstdio>
#include <string>
#include <vector>
@@ -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 <typename Writer>
- 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 <typename Writer>
+ 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 <typename Writer>
- void Serialize(Writer& writer) const {
- writer.StartObject();
-
- writer.String("school");
- writer.String(school_.c_str(), (SizeType)school_.length());
+ template <typename Writer>
+ 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 <typename Writer>
- void Serialize(Writer& writer) const {
- writer.StartObject();
+ template <typename Writer>
+ 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 <typename Writer>
- void Serialize(Writer& writer) const {
- writer.StartObject();
+ template <typename Writer>
+ 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<Dependent>::const_iterator dependentItr = dependents_.begin(); dependentItr != dependents_.end(); ++dependentItr)
- dependentItr->Serialize(writer);
- writer.EndArray();
+ writer.String(("dependents"));
+ writer.StartArray();
+ for (std::vector<Dependent>::const_iterator dependentItr = dependents_.begin(); dependentItr != dependents_.end(); ++dependentItr)
+ dependentItr->Serialize(writer);
+ writer.EndArray();
- writer.EndObject();
- }
+ writer.EndObject();
+ }
private:
- std::vector<Dependent> dependents_;
- bool married_;
+ std::vector<Dependent> dependents_;
+ bool married_;
};
Employee::~Employee() {
}
int main(int, char*[]) {
- std::vector<Employee> employees;
+ std::vector<Employee> 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<FileStream> writer(s); // Can also use Writer for condensed formatting
+ FileStream s(stdout);
+ PrettyWriter<FileStream> writer(s); // Can also use Writer for condensed formatting
- writer.StartArray();
- for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr)
- employeeItr->Serialize(writer);
- writer.EndArray();
+ writer.StartArray();
+ for (std::vector<Employee>::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 a2c9121f..80384199 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<StringBuffer> writer(buffer);
- d.Accept(writer);
+ // 3. Stringify the DOM
+ StringBuffer buffer;
+ Writer<StringBuffer> 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 ed2bd3bf..9914253d 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 98e5b2c3..f8891504 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 c0aca10c..fc96874d 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 <cstdio>
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");
-
- ////////////////////////////////////////////////////////////////////////////
- // 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.
-
- 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;
-
- 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");
-
- 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["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;
-
- // 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()]);
-
- ////////////////////////////////////////////////////////////////////////////
- // 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.
- }
-
- // 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);
- }
-
- // 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() 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<size_t>(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());
-
- assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
-
- ////////////////////////////////////////////////////////////////////////////
- // 4. Stringify JSON
-
- printf("\nModified JSON with reformatting:\n");
- FileStream f(stdout);
- PrettyWriter<FileStream> writer(f);
- document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
-
- return 0;
+ printf("\nParsing to document succeeded.\n");
+
+ ////////////////////////////////////////////////////////////////////////////
+ // 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.
+
+ 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;
+
+ 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");
+
+ 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["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;
+
+ // 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()]);
+
+ ////////////////////////////////////////////////////////////////////////////
+ // 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.
+ }
+
+ // 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);
+ }
+
+ // 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() 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<size_t>(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());
+
+ assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
+
+ ////////////////////////////////////////////////////////////////////////////
+ // 4. Stringify JSON
+
+ printf("\nModified JSON with reformatting:\n");
+ FileStream f(stdout);
+ PrettyWriter<FileStream> writer(f);
+ document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
+
+ return 0;
}
diff --git a/include/rapidjson/allocators.h b/include/rapidjson/allocators.h
index b12c31be..6597a9d5 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().
-
- // 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);
-
- // Free a memory block.
- // \param pointer to the memory block. Null pointer is permitted.
- static void Free(void *ptr);
+ 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);
+
+ // 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);
};
\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 <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
public:
- 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 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.
-
- \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<ChunkHeader*>(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_;
- }
-
- //! 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 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);
-
- void *buffer = reinterpret_cast<char *>(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);
-
- // 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<size_t>(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);
- }
-
- //! Frees a memory block (concept Allocator)
- static void Free(void *ptr) { (void)ptr; } // Do nothing
+ 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 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.
+
+ \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<ChunkHeader*>(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_;
+ }
+
+ //! 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 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);
+
+ void *buffer = reinterpret_cast<char *>(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);
+
+ // 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<size_t>(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);
+ }
+
+ //! 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 */;
-
- //! Creates a new chunk.
- /*! \param capacity Capacity of the chunk in bytes.
- */
- void AddChunk(size_t capacity) {
- ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(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.
-
- //! 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.
+ //! 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<ChunkHeader*>(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.
+
+ //! 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.
};
} // namespace rapidjson
diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
index 1aae6855..880b040e 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 <new> // placement new
+#include <new> // 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 <typename Encoding, typename Allocator>
struct GenericMember {
- GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
- GenericValue<Encoding, Allocator> value; //!< value of member.
+ GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
+ GenericValue<Encoding, Allocator> 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++ <iterator> header.
+ \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+ pointer-based implementation, if your platform doesn't provide
+ the C++ <iterator> header.
- \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
+ \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
*/
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator
- : public std::iterator<std::random_access_iterator_tag
- , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
+ : public std::iterator<std::random_access_iterator_tag
+ , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
- friend class GenericValue<Encoding,Allocator>;
- template <bool, typename, typename> friend class GenericMemberIterator;
+ friend class GenericValue<Encoding,Allocator>;
+ template <bool, typename, typename> friend class GenericMemberIterator;
- typedef GenericMember<Encoding,Allocator> PlainType;
- typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
- typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
+ typedef GenericMember<Encoding,Allocator> PlainType;
+ typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+ typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
public:
- //! Iterator type itself
- typedef GenericMemberIterator Iterator;
- //! Constant iterator type
- typedef GenericMemberIterator<true,Encoding,Allocator> ConstType;
- //! Non-constant iterator type
- typedef GenericMemberIterator<false,Encoding,Allocator> 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;
-
- //! 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
-
- 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_ ) {}
-
- //! @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); }
-
- 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 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_; }
+ //! Iterator type itself
+ typedef GenericMemberIterator Iterator;
+ //! Constant iterator type
+ typedef GenericMemberIterator<true,Encoding,Allocator> ConstType;
+ //! Non-constant iterator type
+ typedef GenericMemberIterator<false,Encoding,Allocator> 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;
+
+ //! 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
+
+ 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_ ) {}
+
+ //! @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); }
+
+ 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 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_; }
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 <typename Encoding, typename Allocator>
struct GenericMemberIterator<false,Encoding,Allocator> {
- //! use plain pointer as iterator type
- typedef GenericMember<Encoding,Allocator>* Iterator;
+ //! use plain pointer as iterator type
+ typedef GenericMember<Encoding,Allocator>* Iterator;
};
//! const GenericMemberIterator
template <typename Encoding, typename Allocator>
struct GenericMemberIterator<true,Encoding,Allocator> {
- //! use plain const pointer as iterator type
- typedef const GenericMember<Encoding,Allocator>* Iterator;
+ //! use plain const pointer as iterator type
+ typedef const GenericMember<Encoding,Allocator>* Iterator;
};
#endif // RAPIDJSON_NOMEMBERITERATORCLASS
@@ -179,143 +199,143 @@ struct GenericMemberIterator<true,Encoding,Allocator> {
//! Reference to a constant string (not taking a copy)
/*!
- \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.
-
- 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
-
- 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
+ \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.
+
+ 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
+
+ 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
*/
template<typename CharType>
struct GenericStringRef {
- 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.
-
- \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
-
- \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<SizeType N>
- 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.
-
- \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
-
- \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)){}
-
- //! 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); }
-
- //! 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)
+ 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.
+
+ \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
+
+ \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<SizeType N>
+ 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.
+
+ \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
+
+ \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)){}
+
+ //! 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); }
+
+ //! 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)
private:
- //! Disallow copy-assignment
- GenericStringRef operator=(const GenericStringRef&);
- //! Disallow construction from non-const array
- template<SizeType N>
- GenericStringRef(CharType (&str)[N]) /* = delete */;
+ //! Disallow copy-assignment
+ GenericStringRef operator=(const GenericStringRef&);
+ //! Disallow construction from non-const array
+ template<SizeType N>
+ 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
-
- \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
+ 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
*/
template<typename CharType>
inline GenericStringRef<CharType> StringRef(const CharType* str) {
- return GenericStringRef<CharType>(str, internal::StrLen(str));
+ return GenericStringRef<CharType>(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.
-
- 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
+ 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.
+
+ \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<typename CharType>
inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
- return GenericStringRef<CharType>(str, SizeType(length));
+ return GenericStringRef<CharType>(str, SizeType(length));
}
///////////////////////////////////////////////////////////////////////////////
@@ -323,1057 +343,1057 @@ inline GenericStringRef<CharType> 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 <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
class GenericValue {
public:
- //! Name-value pair in an object.
- typedef GenericMember<Encoding, Allocator> 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<Ch> StringRefType; //!< Reference to a constant string
- typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
- typedef typename GenericMemberIterator<true,Encoding,Allocator>::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.
- //@{
-
- //! Default constructor creates a null value.
- GenericValue() : data_(), flags_(kNullFlag) {}
+ //! Name-value pair in an object.
+ typedef GenericMember<Encoding, Allocator> 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<Ch> StringRefType; //!< Reference to a constant string
+ typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
+ typedef typename GenericMemberIterator<true,Encoding,Allocator>::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.
+ //@{
+
+ //! 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];
- }
-
- //! 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<Encoding,SourceAllocator>& 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 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<Encoding,SourceAllocator>& 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.
+ */
#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
- template <typename T>
- explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>)))
+ template <typename T>
+ explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<T,bool>)))
#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<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
- flags_ |= kUintFlag;
- if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
- flags_ |= kIntFlag;
- }
- else if (i64 >= static_cast<int64_t>(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<Ch*>(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 <typename T>
- RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,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 <typename SourceAllocator>
- GenericValue& CopyFrom(const GenericValue<Encoding,SourceAllocator>& 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 <typename T> friend bool operator==(const GenericValue& lhs, const T& rhs) { return lhs == GenericValue(rhs); }
- template <typename T> friend bool operator!=(const GenericValue& lhs, const T& rhs) { return !(lhs == rhs); }
- template <typename T> friend bool operator==(const T& lhs, const GenericValue& rhs) { return GenericValue(lhs) == rhs; }
- template <typename T> friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(lhs == rhs); }
- //@}
-
- //!@name Type
- //@{
-
- Type GetType() const { return static_cast<Type>(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<GenericValue&>(*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<GenericValue&>(*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<GenericValue&>(*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<GenericValue&>(*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<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
- }
- else {
- SizeType oldCapacity = o.capacity;
- o.capacity *= 2;
- o.members = reinterpret_cast<Member*>(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 <typename T>
- RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,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<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ flags_ |= kUintFlag;
+ if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ flags_ |= kIntFlag;
+ }
+ else if (i64 >= static_cast<int64_t>(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<Ch*>(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 <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,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 <typename SourceAllocator>
+ GenericValue& CopyFrom(const GenericValue<Encoding,SourceAllocator>& 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 <typename T> friend bool operator==(const GenericValue& lhs, const T& rhs) { return lhs == GenericValue(rhs); }
+ template <typename T> friend bool operator!=(const GenericValue& lhs, const T& rhs) { return !(lhs == rhs); }
+ template <typename T> friend bool operator==(const T& lhs, const GenericValue& rhs) { return GenericValue(lhs) == rhs; }
+ template <typename T> friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(lhs == rhs); }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast<Type>(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<GenericValue&>(*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<GenericValue&>(*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<GenericValue&>(*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<GenericValue&>(*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<Member*>(allocator.Malloc(o.capacity * sizeof(Member)));
+ }
+ else {
+ SizeType oldCapacity = o.capacity;
+ o.capacity *= 2;
+ o.members = reinterpret_cast<Member*>(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 <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,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<GenericValue&>(*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<GenericValue&>(*this).Begin(); }
- //! Constant \em past-the-end element iterator
- /*! \pre IsArray() == true */
- ConstValueIterator End() const { return const_cast<GenericValue&>(*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;
- }
-
- //! 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<StringRefType>(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.
-
- \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 <typename T>
- RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,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 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;
- }
-
- //@}
-
- //!@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; }
-
- 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; }
-
- //@}
-
- //!@name String
- //@{
-
- 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; }
-
- //! 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 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); }
-
- //@}
-
- //! 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 <typename Handler>
- 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 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;
- }
+ */
+ 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<GenericValue&>(*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<GenericValue&>(*this).Begin(); }
+ //! Constant \em past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator End() const { return const_cast<GenericValue&>(*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;
+ }
+
+ //! 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<StringRefType>(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.
+
+ \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 <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,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 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;
+ }
+
+ //@}
+
+ //!@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; }
+
+ 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; }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ 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; }
+
+ //! 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 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); }
+
+ //@}
+
+ //! 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 <typename Handler>
+ 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 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 <typename, typename>
- friend class GenericDocument;
-
- 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,
-
- kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
- };
-
- 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
-
- // By using proper binary layout, retrieval of different integer types do not need conversions.
- union Number {
+ template <typename, typename>
+ friend class GenericDocument;
+
+ 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,
+
+ kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler
+ };
+
+ 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
+
+ // 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
-
- 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
-
- 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 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 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<Ch*>(data_.s.str), s, s.length * sizeof(Ch));
- const_cast<Ch*>(data_.s.str)[s.length] = '\0';
- }
-
- //! 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);
- }
-
- Data data_;
- unsigned flags_;
+ 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 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
+
+ // 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 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<Ch*>(data_.s.str), s, s.length * sizeof(Ch));
+ const_cast<Ch*>(data_.s.str)[s.length] = '\0';
+ }
+
+ //! 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);
+ }
+
+ Data data_;
+ unsigned flags_;
};
#pragma pack (pop)
@@ -1385,218 +1405,218 @@ typedef GenericValue<UTF8<> > 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 <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
class GenericDocument : public GenericValue<Encoding, Allocator> {
public:
- typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
- typedef GenericValue<Encoding, Allocator> 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_() {}
-
- //!@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 <unsigned parseFlags, typename SourceEncoding, typename InputStream>
- GenericDocument& ParseStream(InputStream& is) {
- ValueType::SetNull(); // Remove existing root if exist
- GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
- ClearStackOnExit scope(*this);
- parseResult_ = reader.template Parse<parseFlags>(is, *this);
- if (parseResult_) {
- RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
- this->RawAssign(*stack_.template Pop<ValueType>(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 <unsigned parseFlags, typename InputStream>
- GenericDocument& ParseStream(InputStream& is) {
- return ParseStream<parseFlags,Encoding,InputStream>(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 <typename InputStream>
- GenericDocument& ParseStream(InputStream& is) {
- return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
- }
- //!@}
-
- //!@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 <unsigned parseFlags, typename SourceEncoding>
- GenericDocument& ParseInsitu(Ch* str) {
- GenericInsituStringStream<Encoding> s(str);
- return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(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 <unsigned parseFlags>
- GenericDocument& ParseInsitu(Ch* str) {
- return ParseInsitu<parseFlags, Encoding>(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<kParseDefaultFlags, Encoding>(str);
- }
- //!@}
-
- //!@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 <unsigned parseFlags, typename SourceEncoding>
- GenericDocument& Parse(const Ch* str) {
- RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
- GenericStringStream<SourceEncoding> s(str);
- return ParseStream<parseFlags, SourceEncoding>(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 <unsigned parseFlags>
- GenericDocument& Parse(const Ch* str) {
- return Parse<parseFlags, Encoding>(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<kParseDefaultFlags>(str);
- }
- //!@}
-
- //!@name Handling parse errors
- //!@{
-
- //! 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 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 capacity of stack in bytes.
- size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericValue<Encoding, Allocator> 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_() {}
+
+ //!@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 <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ ValueType::SetNull(); // Remove existing root if exist
+ GenericReader<SourceEncoding, Encoding, Allocator> reader(&GetAllocator());
+ ClearStackOnExit scope(*this);
+ parseResult_ = reader.template Parse<parseFlags>(is, *this);
+ if (parseResult_) {
+ RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+ this->RawAssign(*stack_.template Pop<ValueType>(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 <unsigned parseFlags, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<parseFlags,Encoding,InputStream>(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 <typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+ }
+ //!@}
+
+ //!@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 <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& ParseInsitu(Ch* str) {
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag, SourceEncoding>(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 <unsigned parseFlags>
+ GenericDocument& ParseInsitu(Ch* str) {
+ return ParseInsitu<parseFlags, Encoding>(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<kParseDefaultFlags, Encoding>(str);
+ }
+ //!@}
+
+ //!@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 <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const Ch* str) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ GenericStringStream<SourceEncoding> s(str);
+ return ParseStream<parseFlags, SourceEncoding>(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 <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<parseFlags, Encoding>(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<kParseDefaultFlags>(str);
+ }
+ //!@}
+
+ //!@name Handling parse errors
+ //!@{
+
+ //! 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 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 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_;
- };
-
- // callers of the following private Handler functions
- template <typename,typename,typename> friend class GenericReader; // for parsing
- friend class GenericValue<Encoding,Allocator>; // for deep copying
-
- // Implementation of Handler
- bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
- bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
- bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
-
- bool String(const Ch* str, SizeType length, bool copy) {
- if (copy)
- new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
- else
- new (stack_.template Push<ValueType>()) ValueType(str, length);
- return true;
- }
-
- bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
-
- bool EndObject(SizeType memberCount) {
- typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
- stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
- return true;
- }
-
- bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
-
- bool EndArray(SizeType elementCount) {
- ValueType* elements = stack_.template Pop<ValueType>(elementCount);
- stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
- return true;
- }
+ // 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 <typename,typename,typename> friend class GenericReader; // for parsing
+ friend class GenericValue<Encoding,Allocator>; // for deep copying
+
+ // Implementation of Handler
+ bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
+ bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
+ bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+ bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
+
+ bool String(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ return true;
+ }
+
+ bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
+
+ bool EndObject(SizeType memberCount) {
+ typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+ stack_.template Top<ValueType>()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator());
+ return true;
+ }
+
+ bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
+
+ bool EndArray(SizeType elementCount) {
+ ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+ stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+ return true;
+ }
private:
- //! 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<ValueType>(1))->~ValueType();
- else
- stack_.Clear();
- }
-
- static const size_t kDefaultStackCapacity = 1024;
- internal::Stack<Allocator> stack_;
- ParseResult parseResult_;
+ //! 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<ValueType>(1))->~ValueType();
+ else
+ stack_.Clear();
+ }
+
+ static const size_t kDefaultStackCapacity = 1024;
+ internal::Stack<Allocator> stack_;
+ ParseResult parseResult_;
};
//! GenericDocument with UTF8 encoding
@@ -1608,9 +1628,9 @@ template <typename SourceAllocator>
inline
GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
{
- GenericDocument<Encoding,Allocator> d(&allocator);
- rhs.Accept(d);
- RawAssign(*d.stack_.template Pop<GenericValue>(1));
+ GenericDocument<Encoding,Allocator> d(&allocator);
+ rhs.Accept(d);
+ RawAssign(*d.stack_.template Pop<GenericValue>(1));
}
} // namespace rapidjson
diff --git a/include/rapidjson/encodedstream.h b/include/rapidjson/encodedstream.h
index 83457432..9dc00c7a 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 <typename Encoding, typename InputByteStream>
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 <typename Encoding, typename OutputByteStream>
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<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::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 <typename CharType, typename InputByteStream>
class AutoUTFInputStream {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public:
- 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_);
- }
-
- 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(); }
-
- // 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; }
+ 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_);
+ }
+
+ 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(); }
+
+ // 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&);
-
- // 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;
-
- 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
-
- 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
- }
- }
-
- typedef Ch (*TakeFunc)(InputByteStream& is);
- InputByteStream* is_;
- UTFType type_;
- Ch current_;
- TakeFunc takeFunc_;
- bool hasBOM_;
+ 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
+
+ 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(); }
+
+ // 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.
+ }
+ }
+
+ // 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_;
};
//! 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 <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public:
- 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
- }
-
- static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
- putFunc_ = f[type_];
-
- if (putBOM)
- PutBOM();
- }
-
- UTFType GetType() const { return type_; }
-
- 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; }
+ 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
+ }
+
+ static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
+ putFunc_ = f[type_];
+
+ if (putBOM)
+ PutBOM();
+ }
+
+ UTFType GetType() const { return type_; }
+
+ 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; }
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 2861362e..5c7da3e0 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.
-
- 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<typename OutputStream>
- 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 <typename InputStream>
- 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 <typename InputStream, typename OutputStream>
- static bool Validate(InputStream& is, OutputStream& os);
-
- // The following functions are deal with byte streams.
-
- //! Take a character from input byte stream, skip BOM if exist.
- template <typename InputByteStream>
- static CharType TakeBOM(InputByteStream& is);
-
- //! Take a character from input byte stream.
- template <typename InputByteStream>
- static Ch Take(InputByteStream& is);
-
- //! Put BOM to output byte stream.
- template <typename OutputByteStream>
- static void PutBOM(OutputByteStream& os);
-
- //! Put a character to output byte stream.
- template <typename OutputByteStream>
- static void Put(OutputByteStream& os, Ch c);
+ 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
+
+ //! \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<typename OutputStream>
+ 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 <typename InputStream>
+ 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 <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os);
+
+ // The following functions are deal with byte streams.
+
+ //! Take a character from input byte stream, skip BOM if exist.
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is);
+
+ //! Take a character from input byte stream.
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is);
+
+ //! Put BOM to output byte stream.
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os);
+
+ //! Put a character to output byte stream.
+ template <typename OutputByteStream>
+ 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<typename CharType = char>
struct UTF8 {
- typedef CharType Ch;
-
- enum { supportUnicode = 1 };
-
- template<typename OutputStream>
- static void Encode(OutputStream& os, unsigned codepoint) {
- if (codepoint <= 0x7F)
- os.Put(static_cast<Ch>(codepoint & 0xFF));
- else if (codepoint <= 0x7FF) {
- os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
- os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
- }
- else if (codepoint <= 0xFFFF) {
- os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
- os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
- os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
- }
- else {
- RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
- os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
- os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
- os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
- os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
- }
- }
-
- template <typename InputStream>
- static bool Decode(InputStream& is, unsigned* codepoint) {
+ typedef CharType Ch;
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ if (codepoint <= 0x7F)
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ else if (codepoint <= 0x7FF) {
+ os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+ }
+ else if (codepoint <= 0xFFFF) {
+ os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+ os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+ }
+ }
+
+ template <typename InputStream>
+ 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;
- }
-
- 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;
- }
+ 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;
+ }
#undef COPY
#undef TRANS
#undef TAIL
- }
+ }
- template <typename InputStream, typename OutputStream>
- static bool Validate(InputStream& is, OutputStream& os) {
+ template <typename InputStream, typename OutputStream>
+ 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;
-
- 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;
- }
+ 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;
+ }
#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];
- }
-
- template <typename InputByteStream>
- 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 <typename InputByteStream>
- static Ch Take(InputByteStream& is) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
- return is.Take();
- }
-
- template <typename OutputByteStream>
- static void PutBOM(OutputByteStream& os) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
- os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
- }
-
- template <typename OutputByteStream>
- static void Put(OutputByteStream& os, Ch c) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
- os.Put(static_cast<typename OutputByteStream::Ch>(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 <typename InputByteStream>
+ 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 <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return is.Take();
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(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<typename CharType = wchar_t>
struct UTF16 {
- typedef CharType Ch;
- RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
-
- enum { supportUnicode = 1 };
-
- template<typename OutputStream>
- 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<typename OutputStream::Ch>(codepoint));
- }
- else {
- RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
- unsigned v = codepoint - 0x10000;
- os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
- os.Put((v & 0x3FF) | 0xDC00);
- }
- }
-
- template <typename InputStream>
- 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 <typename InputStream, typename OutputStream>
- 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;
- }
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ 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<typename OutputStream::Ch>(codepoint));
+ }
+ else {
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ unsigned v = codepoint - 0x10000;
+ os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+ os.Put((v & 0x3FF) | 0xDC00);
+ }
+ }
+
+ template <typename InputStream>
+ 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 <typename InputStream, typename OutputStream>
+ 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<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> {
- template <typename InputByteStream>
- 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 <typename InputByteStream>
- 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 <typename OutputByteStream>
- static void PutBOM(OutputByteStream& os) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
- os.Put(0xFFu); os.Put(0xFEu);
- }
-
- template <typename OutputByteStream>
- 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 <typename InputByteStream>
+ 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 <typename InputByteStream>
+ 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 <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0xFFu); os.Put(0xFEu);
+ }
+
+ template <typename OutputByteStream>
+ 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<typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> {
- template <typename InputByteStream>
- 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 <typename InputByteStream>
- 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 <typename OutputByteStream>
- static void PutBOM(OutputByteStream& os) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
- os.Put(0xFEu); os.Put(0xFFu);
- }
-
- template <typename OutputByteStream>
- 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 <typename InputByteStream>
+ 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 <typename InputByteStream>
+ 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 <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(0xFEu); os.Put(0xFFu);
+ }
+
+ template <typename OutputByteStream>
+ 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<CharType> {
//! 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<typename CharType = unsigned>
struct UTF32 {
- typedef CharType Ch;
- RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
-
- enum { supportUnicode = 1 };
-
- template<typename OutputStream>
- static void Encode(OutputStream& os, unsigned codepoint) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
- RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
- os.Put(codepoint);
- }
-
- template <typename InputStream>
- 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 <typename InputStream, typename OutputStream>
- 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;
- }
+ typedef CharType Ch;
+ RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
+
+ enum { supportUnicode = 1 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+ RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+ os.Put(codepoint);
+ }
+
+ template <typename InputStream>
+ 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 <typename InputStream, typename OutputStream>
+ 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<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> {
- template <typename InputByteStream>
- 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 <typename InputByteStream>
- 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 <typename OutputByteStream>
- 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 <typename OutputByteStream>
- 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 <typename InputByteStream>
+ 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 <typename InputByteStream>
+ 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 <typename OutputByteStream>
+ 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 <typename OutputByteStream>
+ 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<typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> {
- template <typename InputByteStream>
- 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 <typename InputByteStream>
- 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 <typename OutputByteStream>
- 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 <typename OutputByteStream>
- 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 <typename InputByteStream>
+ 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 <typename InputByteStream>
+ 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 <typename OutputByteStream>
+ 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 <typename OutputByteStream>
+ 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<CharType> {
//! 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<typename CharType = char>
struct ASCII {
- typedef CharType Ch;
-
- enum { supportUnicode = 0 };
-
- template<typename OutputStream>
- static void Encode(OutputStream& os, unsigned codepoint) {
- RAPIDJSON_ASSERT(codepoint <= 0x7F);
- os.Put(static_cast<Ch>(codepoint & 0xFF));
- }
-
- template <typename InputStream>
- static bool Decode(InputStream& is, unsigned* codepoint) {
- unsigned char c = static_cast<unsigned char>(is.Take());
- *codepoint = c;
- return c <= 0X7F;
- }
-
- template <typename InputStream, typename OutputStream>
- static bool Validate(InputStream& is, OutputStream& os) {
- unsigned char c = is.Take();
- os.Put(c);
- return c <= 0x7F;
- }
-
- template <typename InputByteStream>
- static CharType TakeBOM(InputByteStream& is) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
- Ch c = Take(is);
- return c;
- }
-
- template <typename InputByteStream>
- static Ch Take(InputByteStream& is) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
- return is.Take();
- }
-
- template <typename OutputByteStream>
- static void PutBOM(OutputByteStream& os) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
- (void)os;
- }
-
- template <typename OutputByteStream>
- static void Put(OutputByteStream& os, Ch c) {
- RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
- os.Put(static_cast<typename OutputByteStream::Ch>(c));
- }
+ typedef CharType Ch;
+
+ enum { supportUnicode = 0 };
+
+ template<typename OutputStream>
+ static void Encode(OutputStream& os, unsigned codepoint) {
+ RAPIDJSON_ASSERT(codepoint <= 0x7F);
+ os.Put(static_cast<Ch>(codepoint & 0xFF));
+ }
+
+ template <typename InputStream>
+ static bool Decode(InputStream& is, unsigned* codepoint) {
+ unsigned char c = static_cast<unsigned char>(is.Take());
+ *codepoint = c;
+ return c <= 0X7F;
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static bool Validate(InputStream& is, OutputStream& os) {
+ unsigned char c = is.Take();
+ os.Put(c);
+ return c <= 0x7F;
+ }
+
+ template <typename InputByteStream>
+ static CharType TakeBOM(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ Ch c = Take(is);
+ return c;
+ }
+
+ template <typename InputByteStream>
+ static Ch Take(InputByteStream& is) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+ return is.Take();
+ }
+
+ template <typename OutputByteStream>
+ static void PutBOM(OutputByteStream& os) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ (void)os;
+ }
+
+ template <typename OutputByteStream>
+ static void Put(OutputByteStream& os, Ch c) {
+ RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+ os.Put(static_cast<typename OutputByteStream::Ch>(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<typename CharType>
struct AutoUTF {
- typedef CharType Ch;
+ typedef CharType Ch;
- enum { supportUnicode = 1 };
+ enum { supportUnicode = 1 };
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
- template<typename OutputStream>
- 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 <typename InputStream>
- 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 <typename InputStream, typename OutputStream>
- 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<typename OutputStream>
+ 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 <typename InputStream>
+ 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 <typename InputStream, typename OutputStream>
+ 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<typename SourceEncoding, typename TargetEncoding>
struct Transcoder {
- //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
- template<typename InputStream, typename OutputStream>
- 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<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
- return Transcode(is, os); // Since source/target encoding is different, must transcode.
- }
+ //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
+ template<typename InputStream, typename OutputStream>
+ 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<typename InputStream, typename OutputStream>
+ 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<typename Encoding>
struct Transcoder<Encoding, Encoding> {
- template<typename InputStream, typename OutputStream>
- 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<typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
- return Encoding::Validate(is, os); // source/target encoding are the same
- }
+ template<typename InputStream, typename OutputStream>
+ 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<typename InputStream, typename OutputStream>
+ 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 e9120c5b..b4a3ae1f 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.");
-
- 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 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.");
-
- default:
- return RAPIDJSON_ERROR_STRING("Unknown 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 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 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.");
+ }
}
} // namespace rapidjson
diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h
index 981cbd92..bc5462ab 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 4d42d381..31c193bf 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<size_t>(current_ - buffer_); }
+ Ch Peek() const { return *current_; }
+ Ch Take() { Ch c = *current_; Read(); return c; }
+ size_t Tell() const { return count_ + static_cast<size_t>(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 7e1e3b1f..6995b3d3 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&);
-
- 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_;
+ // 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';
+ }
+
+ FILE* fp_;
+ char current_;
+ size_t count_;
};
} // namespace rapidjson
diff --git a/include/rapidjson/filewritestream.h b/include/rapidjson/filewritestream.h
index 41283113..31ccfc12 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.
-
- 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();
-
- *current_++ = c;
- }
-
- void PutN(char c, size_t n) {
- size_t avail = static_cast<size_t>(bufferEnd_ - current_);
- while (n > avail) {
- memset(current_, c, avail);
- current_ += avail;
- Flush();
- n -= avail;
- avail = static_cast<size_t>(bufferEnd_ - current_);
- }
-
- if (n > 0) {
- memset(current_, c, n);
- current_ += n;
- }
- }
-
- void Flush() {
- if (current_ != buffer_) {
- fwrite(buffer_, 1, static_cast<size_t>(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; }
+ 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);
+ }
+
+ void Put(char c) {
+ if (current_ >= bufferEnd_)
+ Flush();
+
+ *current_++ = c;
+ }
+
+ void PutN(char c, size_t n) {
+ size_t avail = static_cast<size_t>(bufferEnd_ - current_);
+ while (n > avail) {
+ memset(current_, c, avail);
+ current_ += avail;
+ Flush();
+ n -= avail;
+ avail = static_cast<size_t>(bufferEnd_ - current_);
+ }
+
+ if (n > 0) {
+ memset(current_, c, n);
+ current_ += n;
+ }
+ }
+
+ void Flush() {
+ if (current_ != buffer_) {
+ fwrite(buffer_, 1, static_cast<size_t>(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; }
private:
- // Prohibit copy constructor & assignment operator.
- FileWriteStream(const FileWriteStream&);
- FileWriteStream& operator=(const FileWriteStream&);
-
- FILE* fp_;
- char *buffer_;
- char *bufferEnd_;
- char *current_;
+ // Prohibit copy constructor & assignment operator.
+ FileWriteStream(const FileWriteStream&);
+ FileWriteStream& operator=(const FileWriteStream&);
+
+ 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 44f5c115..bef02b01 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(uint64_t f, int e) : f(f), e(e) {}
-
- 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;
- }
- }
-
- DiyFp operator-(const DiyFp& rhs) const {
- return DiyFp(f - rhs.f, e);
- }
-
- DiyFp operator*(const DiyFp& rhs) const {
+ DiyFp() {}
+
+ DiyFp(uint64_t f, int e) : f(f), e(e) {}
+
+ 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;
+ }
+ }
+
+ DiyFp operator-(const DiyFp& rhs) const {
+ return DiyFp(f - rhs.f, e);
+ }
+
+ 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<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f);
- uint64_t h = p >> 64;
- uint64_t l = static_cast<uint64_t>(p);
- if (l & (uint64_t(1) << 63)) // rounding
- h++;
- return DiyFp(h, e + rhs.e + 64);
+ unsigned __int128 p = static_cast<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f);
+ uint64_t h = p >> 64;
+ uint64_t l = static_cast<uint64_t>(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;
- }
-
- 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;
+ }
+
+ 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);
+
+ 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
- };
-
- //int k = static_cast<int>(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<int>(dk);
- if (k != dk)
- k++;
-
- unsigned index = static_cast<unsigned>((k >> 3) + 1);
- *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
-
- return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+ // 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<int>(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<int>(dk);
+ if (k != dk)
+ k++;
+
+ unsigned index = static_cast<unsigned>((k >> 3) + 1);
+ *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
+
+ 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<uint32_t>(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:
+ 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<uint32_t>(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:
#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<char>(d);
- kappa--;
- uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
- if (tmp <= delta) {
- *K += kappa;
- GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
- return;
- }
- }
-
- // kappa = 0
- for (;;) {
- p2 *= 10;
- delta *= 10;
- char d = static_cast<char>(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;
- }
- }
+ }
+ if (d || *len)
+ buffer[(*len)++] = '0' + static_cast<char>(d);
+ kappa--;
+ uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+ if (tmp <= delta) {
+ *K += kappa;
+ GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+ return;
+ }
+ }
+
+ // kappa = 0
+ for (;;) {
+ p2 *= 10;
+ delta *= 10;
+ char d = static_cast<char>(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 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 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);
}
-//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 >= 100) {
- *buffer++ = '0' + static_cast<char>(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<char>(K);
-
- return buffer;
+ if (K < 0) {
+ *buffer++ = '-';
+ K = -K;
+ }
+
+ if (K >= 100) {
+ *buffer++ = '0' + static_cast<char>(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<char>(K);
+
+ return buffer;
}
inline char* Prettify(char* buffer, int length, int k) {
- 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]);
- }
+ 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]);
+ }
}
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 157afb65..2ff199ac 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<uint32_t>(value), buffer);
+ return u32toa(static_cast<uint32_t>(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<uint64_t>(value), buffer);
+ return u64toa(static_cast<uint64_t>(value), buffer);
}
} // namespace internal
diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h
index b8d3295e..62d5224d 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 <typename T> struct IsPointer<T*> : TrueType {};
template <typename CT, typename T>
struct IsMoreConst {
- enum { Value =
- ( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
- && ( IsConst<CT>::Value >= IsConst<T>::Value ) )
- };
+ enum { Value =
+ ( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
+ && ( IsConst<CT>::Value >= IsConst<T>::Value ) )
+ };
};
template <bool Condition, typename T = void> struct EnableIfCond;
@@ -60,15 +80,15 @@ template <typename T> struct RemoveSfinaeFptr {};
template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { 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 \
- <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+ typename ::rapidjson::internal::EnableIf \
+ <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
- typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
+ typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
} // namespace internal
} // namespace rapidjson
diff --git a/include/rapidjson/internal/pow10.h b/include/rapidjson/internal/pow10.h
index d6b92f08..72e0dac9 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 85484655..4ab84b1a 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 <typename Allocator>
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::Free(stack_);
- delete own_allocator_; // Only delete if it is owned by the 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<typename T>
- RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
- // Expand the stack if needed
- if (stack_top_ + sizeof(T) * count >= stack_end_)
- Expand<T>(count);
-
- T* ret = reinterpret_cast<T*>(stack_top_);
- stack_top_ += sizeof(T) * count;
- return ret;
- }
-
- template<typename T>
- T* Pop(size_t count) {
- RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
- stack_top_ -= count * sizeof(T);
- return reinterpret_cast<T*>(stack_top_);
- }
-
- template<typename T>
- T* Top() {
- RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
- return reinterpret_cast<T*>(stack_top_ - sizeof(T));
- }
-
- template<typename T>
- T* Bottom() { return (T*)stack_; }
-
- Allocator& GetAllocator() { return *allocator_; }
- bool Empty() const { return stack_top_ == stack_; }
- size_t GetSize() const { return static_cast<size_t>(stack_top_ - stack_); }
- size_t GetCapacity() const { return 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
+ }
+
+ 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<typename T>
+ RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+ // Expand the stack if needed
+ if (stack_top_ + sizeof(T) * count >= stack_end_)
+ Expand<T>(count);
+
+ T* ret = reinterpret_cast<T*>(stack_top_);
+ stack_top_ += sizeof(T) * count;
+ return ret;
+ }
+
+ template<typename T>
+ T* Pop(size_t count) {
+ RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+ stack_top_ -= count * sizeof(T);
+ return reinterpret_cast<T*>(stack_top_);
+ }
+
+ template<typename T>
+ T* Top() {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stack_top_ - sizeof(T));
+ }
+
+ template<typename T>
+ T* Bottom() { return (T*)stack_; }
+
+ Allocator& GetAllocator() { return *allocator_; }
+ bool Empty() const { return stack_top_ == stack_; }
+ size_t GetSize() const { return static_cast<size_t>(stack_top_ - stack_); }
+ size_t GetCapacity() const { return stack_capacity_; }
private:
- template<typename T>
- 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&);
-
- Allocator* allocator_;
- Allocator* own_allocator_;
- char *stack_;
- char *stack_top_;
- char *stack_end_;
- size_t stack_capacity_;
+ template<typename T>
+ 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&);
+
+ 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 0a20c56f..80adcb6b 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 <typename Ch>
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 3628ebc9..4e820360 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 <typename Allocator = CrtAllocator>
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<Ch>() = c; }
- void Flush() {}
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void Flush() {}
- void Clear() { stack_.Clear(); }
- Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
- void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+ void Clear() { stack_.Clear(); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
- const Ch* GetBuffer() const {
- return stack_.template Bottom<Ch>();
- }
+ const Ch* GetBuffer() const {
+ return stack_.template Bottom<Ch>();
+ }
- size_t GetSize() const { return stack_.GetSize(); }
+ size_t GetSize() const { return stack_.GetSize(); }
- static const size_t kDefaultCapacity = 256;
- mutable internal::Stack<Allocator> stack_;
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> 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<char>(n), c, n * sizeof(c));
+ memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
}
} // namespace rapidjson
diff --git a/include/rapidjson/memorystream.h b/include/rapidjson/memorystream.h
index 158fbb52..8701c33c 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<size_t>(src_ - begin_); }
+ Ch Peek() const { return *src_; }
+ Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
+ size_t Tell() const { return static_cast<size_t>(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 d3514684..b9d75104 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 OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> {
public:
- typedef Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> 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) {}
-
- //! 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
- */
- //@{
-
- 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 StartObject() {
- PrettyPrefix(kObjectType);
- new (Base::level_stack_.template Push<typename Base::Level>()) 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<typename Base::Level>()->inArray);
- bool empty = Base::level_stack_.template Pop<typename Base::Level>(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;
- }
-
- bool StartArray() {
- PrettyPrefix(kArrayType);
- new (Base::level_stack_.template Push<typename Base::Level>()) 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<typename Base::Level>()->inArray);
- bool empty = Base::level_stack_.template Pop<typename Base::Level>(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;
- }
-
- //@}
-
- /*! @name Convenience extensions */
- //@{
-
- //! Simpler but slower overload.
- bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
-
- //@}
+ typedef Writer<OutputStream, SourceEncoding, TargetEncoding, Allocator> 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) {}
+
+ //! 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
+ */
+ //@{
+
+ 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 StartObject() {
+ PrettyPrefix(kObjectType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) 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<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(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;
+ }
+
+ bool StartArray() {
+ PrettyPrefix(kArrayType);
+ new (Base::level_stack_.template Push<typename Base::Level>()) 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<typename Base::Level>()->inArray);
+ bool empty = Base::level_stack_.template Pop<typename Base::Level>(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;
+ }
+
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! 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<typename Base::Level>();
-
- 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;
- }
- }
-
- void WriteIndent() {
- size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
- PutN(*Base::os_, indentChar_, count);
- }
-
- Ch indentChar_;
- unsigned indentCharCount_;
+ 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<typename Base::Level>();
+
+ 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;
+ }
+ }
+
+ void WriteIndent() {
+ size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+ PutN(*Base::os_, indentChar_, count);
+ }
+
+ 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 d25f02b4..0e81e3bf 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 <cstdlib> // malloc(), realloc(), free()
-#include <cstring> // memcpy()
+#include <cstdlib> // malloc(), realloc(), free()
+#include <cstring> // 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 <endian.h>
# 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<uint64_t>(high32) << 32) | static_cast<uint64_t>(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 <cassert>
@@ -180,13 +200,13 @@ template<int x> 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<bool(x) >)>\
- RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+ sizeof(::rapidjson::STATIC_ASSERTION_FAILURE<bool(x) >)>\
+ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -214,7 +234,7 @@ template<int x> 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<typename Stream>
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<StringStream>.
- */
- 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<StringStream>.
+ */
+ enum { copyOptimization = 0 };
};
//! Put N copies of a character to a stream.
template<typename Stream, typename Ch>
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 <typename Encoding>
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<size_t>(src_ - head_); }
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return static_cast<size_t>(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 <typename Encoding>
struct StreamTraits<GenericStringStream<Encoding> > {
- enum { copyOptimization = 1 };
+ enum { copyOptimization = 1 };
};
//! String stream with UTF8 encoding.
@@ -357,37 +377,37 @@ typedef GenericStringStream<UTF8<> > 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 <typename Encoding>
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<size_t>(src_ - head_); }
+ // Read
+ Ch Peek() { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() { return static_cast<size_t>(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<size_t>(dst_ - begin); }
- void Flush() {}
+ Ch* PutBegin() { return dst_ = src_; }
+ size_t PutEnd(Ch* begin) { return static_cast<size_t>(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 <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > {
- enum { copyOptimization = 1 };
+ enum { copyOptimization = 1 };
};
//! Insitu string stream with UTF8 encoding.
@@ -398,13 +418,13 @@ typedef GenericInsituStringStream<UTF8<> > 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 647ecde3..d0f7ea49 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;
-
- 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);
+ 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);
};
\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<typename Encoding = UTF8<> >
struct BaseReaderHandler {
- 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(); }
+ 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(); }
};
///////////////////////////////////////////////////////////////////////////////
@@ -133,27 +153,27 @@ class StreamLocalCopy;
template<typename Stream>
class StreamLocalCopy<Stream, 1> {
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<typename Stream>
class StreamLocalCopy<Stream, 0> {
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<typename InputStream>
void SkipWhitespace(InputStream& is) {
- internal::StreamLocalCopy<InputStream> copy(is);
- InputStream& s(copy.s);
+ internal::StreamLocalCopy<InputStream> 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"};
-
- // 16-byte align to the lower boundary
- const char* ap = reinterpret_cast<const char*>(reinterpret_cast<size_t>(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]);
-
- unsigned char shift = reinterpret_cast<size_t>(p) & 15;
- const __m128i s = _mm_load_si128(reinterpret_cast<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);
- 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;
+ 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<const char*>(reinterpret_cast<size_t>(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]);
+
+ unsigned char shift = reinterpret_cast<size_t>(p) & 15;
+ const __m128i s = _mm_load_si128(reinterpret_cast<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);
+ 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;
- }
-
- 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;
+ }
+ ap += 16;
+ }
+
+ 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;
#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"};
-
- 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<const char*>(reinterpret_cast<size_t>(p) & ~15);
-
- // Test first unaligned characters
- if (ap != p) {
- unsigned char shift = reinterpret_cast<size_t>(p) & 15;
- const __m128i s = _mm_load_si128(reinterpret_cast<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);
- 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;
+ 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]);
+
+ // 16-byte align to the lower boundary
+ const char* ap = reinterpret_cast<const char*>(reinterpret_cast<size_t>(p) & ~15);
+
+ // Test first unaligned characters
+ if (ap != p) {
+ unsigned char shift = reinterpret_cast<size_t>(p) & 15;
+ const __m128i s = _mm_load_si128(reinterpret_cast<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);
+ 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;
- }
-
- // 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;
+ }
+ 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;
#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<char*>(SkipWhitespace_SIMD(is.src_));
+ is.src_ = const_cast<char*>(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 <typename SourceEncoding, typename TargetEncoding, typename Allocator = MemoryPoolAllocator<> >
class GenericReader {
public:
- 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_() {}
-
- //! 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 <unsigned parseFlags, typename InputStream, typename Handler>
- ParseResult Parse(InputStream& is, Handler& handler) {
- if (parseFlags & kParseIterativeFlag)
- return IterativeParse<parseFlags>(is, handler);
-
- parseResult_.Clear();
-
- ClearStackOnExit scope(*this);
-
- 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<parseFlags>(is, handler); break;
- case '[': ParseArray<parseFlags>(is, handler); break;
- default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
- }
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
-
- if (!(parseFlags & kParseStopWhenDoneFlag)) {
- SkipWhitespace(is);
-
- if (is.Peek() != '\0') {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
- RAPIDJSON_PARSE_ERROR_EARLY_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 <typename InputStream, typename Handler>
- ParseResult Parse(InputStream& is, Handler& handler) {
- return Parse<kParseDefaultFlags>(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(); }
-
- //! Get the position of last parsing error in input, 0 otherwise.
- size_t GetErrorOffset() const { return parseResult_.Offset(); }
+ 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_() {}
+
+ //! 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 <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ if (parseFlags & kParseIterativeFlag)
+ return IterativeParse<parseFlags>(is, handler);
+
+ parseResult_.Clear();
+
+ ClearStackOnExit scope(*this);
+
+ 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<parseFlags>(is, handler); break;
+ case '[': ParseArray<parseFlags>(is, handler); break;
+ default: RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotObjectOrArray, is.Tell());
+ }
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (!(parseFlags & kParseStopWhenDoneFlag)) {
+ SkipWhitespace(is);
+
+ if (is.Peek() != '\0') {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_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 <typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ return Parse<kParseDefaultFlags>(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(); }
+
+ //! 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&);
-
- 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&);
- };
-
- // Parse object: { string : value, ... }
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseObject(InputStream& is, Handler& handler) {
- RAPIDJSON_ASSERT(is.Peek() == '{');
- is.Take(); // Skip '{'
-
- if (!handler.StartObject())
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
-
- SkipWhitespace(is);
-
- 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());
-
- ParseString<parseFlags>(is, handler);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- SkipWhitespace(is);
-
- if (is.Take() != ':')
- RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
-
- SkipWhitespace(is);
-
- ParseValue<parseFlags>(is, handler);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- SkipWhitespace(is);
-
- ++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());
- }
- }
- }
-
- // Parse array: [ value, ... ]
- template<unsigned parseFlags, typename InputStream, typename Handler>
- 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;
- }
-
- for (SizeType elementCount = 0;;) {
- ParseValue<parseFlags>(is, handler);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- ++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());
- }
- }
- }
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- 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);
- }
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- 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);
- }
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- 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);
- }
-
- // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
- template<typename InputStream>
- unsigned ParseHex4(InputStream& is) {
- unsigned codepoint = 0;
- for (int i = 0; i < 4; i++) {
- Ch c = is.Take();
- codepoint <<= 4;
- codepoint += static_cast<unsigned>(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;
-
- StackStream(internal::Stack<Allocator>& stack) : stack_(stack), length_(0) {}
- RAPIDJSON_FORCEINLINE void Put(Ch c) {
- *stack_.template Push<Ch>() = c;
- ++length_;
- }
- internal::Stack<Allocator>& stack_;
- SizeType length_;
-
- private:
- StackStream(const StackStream&);
- StackStream& operator=(const StackStream&);
- };
-
- // Parse string and generate String event. Different code paths for kParseInsituFlag.
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseString(InputStream& is, Handler& handler) {
- internal::StreamLocalCopy<InputStream> copy(is);
- InputStream& s(copy.s);
-
- if (parseFlags & kParseInsituFlag) {
- typename InputStream::Ch *head = s.PutBegin();
- ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(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<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- if (!handler.String(stack_.template Pop<typename TargetEncoding::Ch>(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<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
+ // Prohibit copy constructor & assignment operator.
+ GenericReader(const GenericReader&);
+ GenericReader& operator=(const GenericReader&);
+
+ 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&);
+ };
+
+ // Parse object: { string : value, ... }
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseObject(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '{');
+ is.Take(); // Skip '{'
+
+ if (!handler.StartObject())
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespace(is);
+
+ 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());
+
+ ParseString<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespace(is);
+
+ if (is.Take() != ':')
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+
+ SkipWhitespace(is);
+
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespace(is);
+
+ ++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());
+ }
+ }
+ }
+
+ // Parse array: [ value, ... ]
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ 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;
+ }
+
+ for (SizeType elementCount = 0;;) {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++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());
+ }
+ }
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ 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);
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ 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);
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ 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);
+ }
+
+ // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+ template<typename InputStream>
+ unsigned ParseHex4(InputStream& is) {
+ unsigned codepoint = 0;
+ for (int i = 0; i < 4; i++) {
+ Ch c = is.Take();
+ codepoint <<= 4;
+ codepoint += static_cast<unsigned>(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;
+
+ StackStream(internal::Stack<Allocator>& stack) : stack_(stack), length_(0) {}
+ RAPIDJSON_FORCEINLINE void Put(Ch c) {
+ *stack_.template Push<Ch>() = c;
+ ++length_;
+ }
+ internal::Stack<Allocator>& stack_;
+ SizeType length_;
+
+ private:
+ StackStream(const StackStream&);
+ StackStream& operator=(const StackStream&);
+ };
+
+ // Parse string and generate String event. Different code paths for kParseInsituFlag.
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseString(InputStream& is, Handler& handler) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ if (parseFlags & kParseInsituFlag) {
+ typename InputStream::Ch *head = s.PutBegin();
+ ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(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<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (!handler.String(stack_.template Pop<typename TargetEncoding::Ch>(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<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
+ 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 '\"'
-
- 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<SEncoding, TEncoding>::Validate(is, os) :
- !Transcoder<SEncoding, TEncoding>::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);
- }
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseNumber(InputStream& is, Handler& handler) {
- internal::StreamLocalCopy<InputStream> copy(is);
- InputStream& s(copy.s);
-
- // 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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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();
-
- 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();
- }
- }
-
- // 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;
- }
-
- 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;
- }
-
- // 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());
- }
-
- // Parse any JSON value
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseValue(InputStream& is, Handler& handler) {
- switch (is.Peek()) {
- case 'n': ParseNull <parseFlags>(is, handler); break;
- case 't': ParseTrue <parseFlags>(is, handler); break;
- case 'f': ParseFalse <parseFlags>(is, handler); break;
- case '"': ParseString<parseFlags>(is, handler); break;
- case '{': ParseObject<parseFlags>(is, handler); break;
- case '[': ParseArray <parseFlags>(is, handler); break;
- default : ParseNumber<parseFlags>(is, handler);
- }
- }
-
- // Iterative Parsing
-
- // States
- enum IterativeParsingState {
- IterativeParsingStartState = 0,
- IterativeParsingFinishState,
- IterativeParsingErrorState,
-
- // Object states
- IterativeParsingObjectInitialState,
- IterativeParsingMemberKeyState,
- IterativeParsingKeyValueDelimiterState,
- IterativeParsingMemberValueState,
- IterativeParsingMemberDelimiterState,
- IterativeParsingObjectFinishState,
-
- // Array states
- IterativeParsingArrayInitialState,
- IterativeParsingElementState,
- IterativeParsingElementDelimiterState,
- IterativeParsingArrayFinishState,
-
- cIterativeParsingStateCount
- };
-
- // Tokens
- enum Token {
- LeftBracketToken = 0,
- RightBracketToken,
-
- LeftCurlyBracketToken,
- RightCurlyBracketToken,
-
- CommaToken,
- ColonToken,
-
- StringToken,
- FalseToken,
- TrueToken,
- NullToken,
- NumberToken,
-
- kTokenCount
- };
-
- RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+ 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<SEncoding, TEncoding>::Validate(is, os) :
+ !Transcoder<SEncoding, TEncoding>::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);
+ }
+
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNumber(InputStream& is, Handler& handler) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ // 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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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<unsigned>(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();
+
+ 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();
+ }
+ }
+
+ // 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;
+ }
+
+ 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;
+ }
+
+ // 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());
+ }
+
+ // Parse any JSON value
+ template<unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseValue(InputStream& is, Handler& handler) {
+ switch (is.Peek()) {
+ case 'n': ParseNull <parseFlags>(is, handler); break;
+ case 't': ParseTrue <parseFlags>(is, handler); break;
+ case 'f': ParseFalse <parseFlags>(is, handler); break;
+ case '"': ParseString<parseFlags>(is, handler); break;
+ case '{': ParseObject<parseFlags>(is, handler); break;
+ case '[': ParseArray <parseFlags>(is, handler); break;
+ default : ParseNumber<parseFlags>(is, handler);
+ }
+ }
+
+ // Iterative Parsing
+
+ // States
+ enum IterativeParsingState {
+ IterativeParsingStartState = 0,
+ IterativeParsingFinishState,
+ IterativeParsingErrorState,
+
+ // Object states
+ IterativeParsingObjectInitialState,
+ IterativeParsingMemberKeyState,
+ IterativeParsingKeyValueDelimiterState,
+ IterativeParsingMemberValueState,
+ IterativeParsingMemberDelimiterState,
+ IterativeParsingObjectFinishState,
+
+ // Array states
+ IterativeParsingArrayInitialState,
+ IterativeParsingElementState,
+ IterativeParsingElementDelimiterState,
+ IterativeParsingArrayFinishState,
+
+ cIterativeParsingStateCount
+ };
+
+ // Tokens
+ enum Token {
+ LeftBracketToken = 0,
+ RightBracketToken,
+
+ LeftCurlyBracketToken,
+ RightCurlyBracketToken,
+
+ CommaToken,
+ ColonToken,
+
+ StringToken,
+ FalseToken,
+ TrueToken,
+ NullToken,
+ NumberToken,
+
+ kTokenCount
+ };
+
+ 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;
- }
-
- 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];
- }
-
- // 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 <unsigned parseFlags, typename InputStream, typename Handler>
- 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 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<SizeType>(1) = n;
- // Initialize and push the member/element count.
- *stack_.template Push<SizeType>(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<parseFlags>(is, handler);
- if (HasParseError())
- return IterativeParsingErrorState;
- else
- return dst;
-
- 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<parseFlags>(is, handler);
- if (HasParseError()) {
- return IterativeParsingErrorState;
- }
- return dst;
-
- case IterativeParsingElementState:
- // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
- ParseValue<parseFlags>(is, handler);
- if (HasParseError()) {
- return IterativeParsingErrorState;
- }
- return dst;
-
- case IterativeParsingMemberDelimiterState:
- case IterativeParsingElementDelimiterState:
- is.Take();
- // Update member/element count.
- *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
- return dst;
-
- case IterativeParsingObjectFinishState:
- {
- // Get member count.
- SizeType c = *stack_.template Pop<SizeType>(1);
- // If the object is not empty, count the last member.
- if (src == IterativeParsingMemberValueState)
- ++c;
- // Restore the state.
- IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(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<SizeType>(1);
- // If the array is not empty, count the last element.
- if (src == IterativeParsingElementState)
- ++c;
- // Restore the state.
- IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(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;
- }
- }
-
- template <typename InputStream>
- 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 <unsigned parseFlags, typename InputStream, typename Handler>
- 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<parseFlags>(state, t, n, is, handler);
-
- if (d == IterativeParsingErrorState) {
- HandleError(state, is);
- break;
- }
-
- state = d;
-
- // Do not further consume streams if a root JSON has been parsed.
- if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
- break;
-
- SkipWhitespace(is);
- }
-
- // Handle the end of file.
- if (state != IterativeParsingFinishState)
- HandleError(state, is);
-
- return parseResult_;
- }
-
- static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
- internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
- ParseResult parseResult_;
+
+ 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
+
+ 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 <unsigned parseFlags, typename InputStream, typename Handler>
+ 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 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<SizeType>(1) = n;
+ // Initialize and push the member/element count.
+ *stack_.template Push<SizeType>(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<parseFlags>(is, handler);
+ if (HasParseError())
+ return IterativeParsingErrorState;
+ else
+ return dst;
+
+ 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<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingElementState:
+ // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingMemberDelimiterState:
+ case IterativeParsingElementDelimiterState:
+ is.Take();
+ // Update member/element count.
+ *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
+ return dst;
+
+ case IterativeParsingObjectFinishState:
+ {
+ // Get member count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the object is not empty, count the last member.
+ if (src == IterativeParsingMemberValueState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(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<SizeType>(1);
+ // If the array is not empty, count the last element.
+ if (src == IterativeParsingElementState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(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;
+ }
+ }
+
+ template <typename InputStream>
+ 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 <unsigned parseFlags, typename InputStream, typename Handler>
+ 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<parseFlags>(state, t, n, is, handler);
+
+ if (d == IterativeParsingErrorState) {
+ HandleError(state, is);
+ break;
+ }
+
+ state = d;
+
+ // Do not further consume streams if a root JSON has been parsed.
+ if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
+ break;
+
+ SkipWhitespace(is);
+ }
+
+ // Handle the end of file.
+ if (state != IterativeParsingFinishState)
+ HandleError(state, is);
+
+ return parseResult_;
+ }
+
+ static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
+ internal::Stack<Allocator> 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 0e89f959..b8d7968c 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 <typename Encoding, typename Allocator = CrtAllocator>
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<Ch>() = c; }
- void Flush() {}
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void Flush() {}
- void Clear() { stack_.Clear(); }
- Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
- void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+ void Clear() { stack_.Clear(); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
- const Ch* GetString() const {
- // Push and pop a null terminator. This is safe.
- *stack_.template Push<Ch>() = '\0';
- stack_.template Pop<Ch>(1);
+ const Ch* GetString() const {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.template Pop<Ch>(1);
- return stack_.template Bottom<Ch>();
- }
+ return stack_.template Bottom<Ch>();
+ }
- size_t GetSize() const { return stack_.GetSize(); }
+ size_t GetSize() const { return stack_.GetSize(); }
- static const size_t kDefaultCapacity = 256;
- mutable internal::Stack<Allocator> stack_;
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
};
//! String buffer with UTF8 encoding
@@ -45,7 +65,7 @@ typedef GenericStringBuffer<UTF8<> > StringBuffer;
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
- memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+ memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
}
} // namespace rapidjson
diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h
index 9d25b276..9fdfde21 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 <new> // placement new
+#include <new> // 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 OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
class Writer {
public:
- 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) {}
-
- 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.
-
- \param os New output stream.
- \code
- Writer<OutputStream> 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();
- }
-
- //! 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
- */
- //@{
-
- 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); }
-
- 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>()) Level(false);
- return WriteStartObject();
- }
-
- bool EndObject(SizeType memberCount = 0) {
- (void)memberCount;
- RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
- RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
- level_stack_.template Pop<Level>(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>()) Level(true);
- return WriteStartArray();
- }
-
- bool EndArray(SizeType elementCount = 0) {
- (void)elementCount;
- RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
- RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
- level_stack_.template Pop<Level>(1);
- bool ret = WriteEndArray();
- if (level_stack_.Empty()) // end of json text
- os_->Flush();
- return ret;
- }
- //@}
-
- /*! @name Convenience extensions */
- //@{
-
- //! Simpler but slower overload.
- bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
-
- //@}
+ 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) {}
+
+ 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.
+
+ \param os New output stream.
+ \code
+ Writer<OutputStream> 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();
+ }
+
+ //! 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
+ */
+ //@{
+
+ 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); }
+
+ 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>()) Level(false);
+ return WriteStartObject();
+ }
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(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>()) Level(true);
+ return WriteStartArray();
+ }
+
+ bool EndArray(SizeType elementCount = 0) {
+ (void)elementCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ bool ret = WriteEndArray();
+ if (level_stack_.Empty()) // end of json text
+ os_->Flush();
+ return ret;
+ }
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! 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
- };
-
- static const size_t kDefaultLevelDepth = 32;
-
- 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 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 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 WriteDouble(double d) {
- char buffer[25];
- char* end = internal::dtoa(d, buffer);
- for (char* p = buffer; p != end; ++p)
- os_->Put(*p);
- return true;
- }
+ //! 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;
+
+ 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 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 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 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<SourceEncoding> 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<SourceEncoding, TargetEncoding>::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; }
-
- void Prefix(Type type) {
- (void)type;
- if (level_stack_.GetSize() != 0) { // this value is not at root
- Level* level = level_stack_.template Top<Level>();
- 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<Allocator> level_stack_;
- bool hasRoot_;
+ };
+
+ os_->Put('\"');
+ GenericStringStream<SourceEncoding> 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<SourceEncoding, TargetEncoding>::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; }
+
+ void Prefix(Type type) {
+ (void)type;
+ if (level_stack_.GetSize() != 0) { // this value is not at root
+ Level* level = level_stack_.template Top<Level>();
+ 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<Allocator> 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<StringBuffer>::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<StringBuffer>::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<StringBuffer>::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<StringBuffer>::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<StringBuffer>::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 1f5add42..2ce5b8a3 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 dfa50f83..fe2d9478 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 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 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,
};
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<typename OutputStream>
class Writer1 {
public:
- Writer1() : os_() {}
- Writer1(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 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;
- }
-
- 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);
-
- do {
- --p;
- os_->Put(*p);
- } while (p != buffer);
- return true;
- }
+ Writer1() : os_() {}
+ Writer1(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 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;
+ }
+
+ 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);
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
private:
- OutputStream* os_;
+ OutputStream* os_;
};
template<>
bool Writer1<rapidjson::StringBuffer>::WriteUint(unsigned u) {
- 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 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;
}
// Using digits LUT to reduce divsion/modulo
template<typename OutputStream>
class Writer2 {
public:
- Writer2() : os_() {}
- Writer2(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 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;
- }
-
- 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<unsigned>(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<unsigned>(u64) << 1;
- *p++ = digits[i + 1];
- *p++ = digits[i];
- }
-
- do {
- --p;
- os_->Put(*p);
- } while (p != buffer);
- return true;
- }
+ Writer2() : os_() {}
+ Writer2(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 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;
+ }
+
+ 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<unsigned>(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<unsigned>(u64) << 1;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+
+ do {
+ --p;
+ os_->Put(*p);
+ } while (p != buffer);
+ return true;
+ }
private:
- OutputStream* os_;
+ OutputStream* os_;
};
// First pass to count digits
template<typename OutputStream>
class Writer3 {
public:
- Writer3() : os_() {}
- Writer3(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 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;
- }
-
- 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);
-
- do {
- --p;
- os_->Put(*p);
- } while (p != buffer);
- return true;
- }
+ Writer3() : os_() {}
+ Writer3(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 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;
+ }
+
+ 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);
+
+ 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 WriteUint64Reverse(char* d, uint64_t u) {
- do {
- *--d = char(u % 10) + '0';
- u /= 10;
- } while (u > 0);
- }
-
- OutputStream* os_;
+ 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);
+ }
+
+ OutputStream* os_;
};
template<>
inline bool Writer3<rapidjson::StringBuffer>::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<rapidjson::InsituStringStream>::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<rapidjson::StringBuffer>::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<rapidjson::InsituStringStream>::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<typename OutputStream>
class Writer4 {
public:
- Writer4() : os_() {}
- Writer4(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 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;
- }
-
- 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<unsigned>(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<unsigned>(u64) << 1;
- *p++ = digits[i + 1];
- *p++ = digits[i];
- }
-
- do {
- --p;
- os_->Put(*p);
- } while (p != buffer);
- return true;
- }
+ Writer4() : os_() {}
+ Writer4(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 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;
+ }
+
+ 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<unsigned>(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<unsigned>(u64) << 1;
+ *p++ = digits[i + 1];
+ *p++ = digits[i];
+ }
+
+ 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 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_;
+ 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];
+ }
+ }
+
+ OutputStream* os_;
};
template<>
inline bool Writer4<rapidjson::StringBuffer>::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<rapidjson::InsituStringStream>::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<rapidjson::StringBuffer>::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<rapidjson::InsituStringStream>::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 <typename Writer>
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 <typename Writer>
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 <typename Writer>
void itoa_Writer_StringBuffer() {
- size_t length = 0;
-
- 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);
+ size_t length = 0;
+
+ 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);
}
template <typename Writer>
void itoa_Writer_InsituStringStream() {
- 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);
+ 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);
};
template <typename Writer>
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 <typename Writer>
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 <typename Writer>
void itoa64_Writer_StringBuffer() {
- size_t length = 0;
-
- 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);
+ size_t length = 0;
+
+ 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);
}
template <typename Writer>
void itoa64_Writer_InsituStringStream() {
- 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);
+ 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);
};
// Full specialization for InsituStringStream to prevent memory copying
@@ -907,34 +927,34 @@ namespace rapidjson {
template<>
bool rapidjson::Writer<InsituStringStream>::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<InsituStringStream>::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<InsituStringStream>::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<InsituStringStream>::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<Writer4<rapidjson::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 fac4c2f8..4366e1c1 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 be369202..81b4011f 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_() {}
-
- 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);
-
- // 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;
- }
+ 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);
+
+ 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';
+ }
+
+ 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 badb0c9e..30b690c1 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();
-
- // 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;
- }
-
- virtual void TearDown() {
- PerfTest::TearDown();
- free(temp_);
- }
+ virtual void SetUp() {
+ PerfTest::SetUp();
+
+ // 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;
+ }
+
+ 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 95a407d5..6a451131 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<kParseInsituFlag>(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<kParseInsituFlag>(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<kParseInsituFlag | kParseValidateEncodingFlag>(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<kParseInsituFlag | kParseValidateEncodingFlag>(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<kParseIterativeFlag>(s, h));
- }
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream s(json_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseIterativeFlag>(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<kParseIterativeFlag|kParseInsituFlag>(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<kParseIterativeFlag|kParseInsituFlag>(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<kParseValidateEncodingFlag>(s, h));
- }
+ for (size_t i = 0; i < kTrialCount; i++) {
+ StringStream s(json_);
+ BaseReaderHandler<> h;
+ Reader reader;
+ EXPECT_TRUE(reader.Parse<kParseValidateEncodingFlag>(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<kParseIterativeFlag>(temp_);
- ASSERT_TRUE(doc.IsObject());
- }
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ Document doc;
+ doc.ParseInsitu<kParseIterativeFlag>(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<kParseIterativeFlag>(json_);
- ASSERT_TRUE(doc.IsObject());
- }
+ for (size_t i = 0; i < kTrialCount; i++) {
+ Document doc;
+ doc.Parse<kParseIterativeFlag>(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<UTF8<>, CrtAllocator> doc;
- doc.Parse(temp_);
- ASSERT_TRUE(doc.IsObject());
- }
+ for (size_t i = 0; i < kTrialCount; i++) {
+ memcpy(temp_, json_, length_ + 1);
+ GenericDocument<UTF8<>, CrtAllocator> doc;
+ doc.Parse(temp_);
+ ASSERT_TRUE(doc.IsObject());
+ }
}
template<typename T>
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;
-
- case kArrayType:
- for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr)
- count += Traverse(*itr);
- break;
-
- default:
- // Do nothing.
- break;
- }
- return count;
+ 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;
+
+ 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<NullStream> 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<NullStream> 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<StringBuffer> 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<StringBuffer> 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<StringBuffer> 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<StringBuffer> 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;
-
- 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);
- }
+ 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);
+ }
}
// 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 8328c63b..028fcdcd 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 87173161..32d851ad 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));
-
- 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)
+ 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)
#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);
- }
-
- 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;
- }
-
- 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;
+ //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_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);
+
+ 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);
-
- 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);
- }
+ 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();
+ }
+
+ 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, " ");
-
- 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);
- }
+ 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();
+ }
+
+ 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 fbd035b8..0606ccf4 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<UTF8<>, FileReadStream> eis(bis);
-
- GenericDocument<UTF16<> > d;
- d.ParseStream<0, UTF8<> >(eis);
- EXPECT_FALSE(d.HasParseError());
-
- fclose(fp);
-
- wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
- GenericValue<UTF16<> >& 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<UTF8<>, StringBuffer> OutputStream;
- OutputStream eos(bos, false); // Not writing BOM
- Writer<OutputStream, UTF16<>, 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<StringBuffer> writer(bos2);
- reader.Parse(is, writer);
-
- EXPECT_EQ(bos.GetSize(), bos2.GetSize());
- EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
- }
+ // UTF8 -> UTF16
+ FILE* fp = OpenEncodedFile("utf8.json");
+ char buffer[256];
+ FileReadStream bis(fp, buffer, sizeof(buffer));
+ EncodedInputStream<UTF8<>, FileReadStream> eis(bis);
+
+ GenericDocument<UTF16<> > d;
+ d.ParseStream<0, UTF8<> >(eis);
+ EXPECT_FALSE(d.HasParseError());
+
+ fclose(fp);
+
+ wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
+ GenericValue<UTF16<> >& 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<UTF8<>, StringBuffer> OutputStream;
+ OutputStream eos(bos, false); // Not writing BOM
+ Writer<OutputStream, UTF16<>, 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<StringBuffer> writer(bos2);
+ reader.Parse(is, writer);
+
+ 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<unsigned, FileReadStream> eis(bis);
-
- Document d;
- d.ParseStream<0, AutoUTF<unsigned> >(eis);
- EXPECT_FALSE(d.HasParseError());
-
- 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()));
-
- // UTF8 -> UTF8 in memory
- StringBuffer bos;
- Writer<StringBuffer> 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<StringBuffer> writer(bos2);
- reader.Parse(is, writer);
-
- EXPECT_EQ(bos.GetSize(), bos2.GetSize());
- EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
- }
+ // Any -> UTF8
+ FILE* fp = OpenEncodedFile("utf32be.json");
+ char buffer[256];
+ FileReadStream bis(fp, buffer, sizeof(buffer));
+ AutoUTFInputStream<unsigned, FileReadStream> eis(bis);
+
+ Document d;
+ d.ParseStream<0, AutoUTF<unsigned> >(eis);
+ EXPECT_FALSE(d.HasParseError());
+
+ 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()));
+
+ // UTF8 -> UTF8 in memory
+ StringBuffer bos;
+ Writer<StringBuffer> 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<StringBuffer> writer(bos2);
+ reader.Parse(is, writer);
+
+ 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<OutputStringStream> writer(os);
- doc.Accept(writer);
+ OutputStringStream os;
+ Writer<OutputStringStream> 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<kParseValidateEncodingFlag>(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]");
+ GenericDocument< UTF16<> > json;
+ json.Parse<kParseValidateEncodingFlag>(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 4e4db2d2..a29cb3bc 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 <typename FileEncoding, typename MemoryEncoding>
- 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<FileEncoding, FileReadStream> eis(fs);
- StringStream s(json_);
+ template <typename FileEncoding, typename MemoryEncoding>
+ 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<FileEncoding, FileReadStream> 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<FileEncoding, MemoryStream> eis(ms);
- StringStream s(json_);
+ // Test MemoryStream
+ {
+ size_t size;
+ char* data = ReadFile(filename, true, &size);
+ MemoryStream ms(data, size);
+ EncodedInputStream<FileEncoding, MemoryStream> 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<unsigned, FileReadStream> eis(fs);
- StringStream s(json_);
- while (eis.Peek() != '\0') {
- unsigned expected, actual;
- EXPECT_TRUE(UTF8<>::Decode(s, &expected));
- EXPECT_TRUE(AutoUTF<unsigned>::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<unsigned, FileReadStream> eis(fs);
+ StringStream s(json_);
+ while (eis.Peek() != '\0') {
+ unsigned expected, actual;
+ EXPECT_TRUE(UTF8<>::Decode(s, &expected));
+ EXPECT_TRUE(AutoUTF<unsigned>::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<unsigned, MemoryStream> eis(ms);
- StringStream s(json_);
+ // Test MemoryStream
+ {
+ size_t size;
+ char* data = ReadFile(filename, true, &size);
+ MemoryStream ms(data, size);
+ AutoUTFInputStream<unsigned, MemoryStream> eis(ms);
+ StringStream s(json_);
- while (eis.Peek() != '\0') {
- unsigned expected, actual;
- EXPECT_TRUE(UTF8<>::Decode(s, &expected));
- EXPECT_TRUE(AutoUTF<unsigned>::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<unsigned>::Decode(eis, &actual));
+ EXPECT_EQ(expected, actual);
+ }
+ EXPECT_EQ('\0', s.Peek());
+ free(data);
+ }
+ }
- template <typename FileEncoding, typename MemoryEncoding>
- void TestEncodedOutputStream(const char* expectedFilename, bool putBOM) {
- // Test FileWriteStream
- {
- char filename[L_tmpnam];
- TempFilename(filename);
+ template <typename FileEncoding, typename MemoryEncoding>
+ 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<FileEncoding, FileWriteStream> eos(os, putBOM);
- StringStream s(json_);
- while (s.Peek() != '\0') {
- bool success = Transcoder<UTF8<>, 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<FileEncoding, FileWriteStream> eos(os, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, MemoryEncoding>::Transcode(s, eos);
+ EXPECT_TRUE(success);
+ }
+ eos.Flush();
+ fclose(fp);
+ EXPECT_TRUE(CompareFile(filename, expectedFilename));
+ remove(filename);
+ }
- // Test MemoryBuffer
- {
- MemoryBuffer mb;
- EncodedOutputStream<FileEncoding, MemoryBuffer> eos(mb, putBOM);
- StringStream s(json_);
- while (s.Peek() != '\0') {
- bool success = Transcoder<UTF8<>, MemoryEncoding>::Transcode(s, eos);
- EXPECT_TRUE(success);
- }
- eos.Flush();
- EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename));
- }
- }
+ // Test MemoryBuffer
+ {
+ MemoryBuffer mb;
+ EncodedOutputStream<FileEncoding, MemoryBuffer> eos(mb, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, 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<unsigned, FileWriteStream> eos(os, type, putBOM);
- StringStream s(json_);
- while (s.Peek() != '\0') {
- bool success = Transcoder<UTF8<>, AutoUTF<unsigned> >::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<unsigned, FileWriteStream> eos(os, type, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, AutoUTF<unsigned> >::Transcode(s, eos);
+ EXPECT_TRUE(success);
+ }
+ eos.Flush();
+ fclose(fp);
+ EXPECT_TRUE(CompareFile(filename, expectedFilename));
+ remove(filename);
+ }
- // Test MemoryBuffer
- {
- MemoryBuffer mb;
- AutoUTFOutputStream<unsigned, MemoryBuffer> eos(mb, type, putBOM);
- StringStream s(json_);
- while (s.Peek() != '\0') {
- bool success = Transcoder<UTF8<>, AutoUTF<unsigned> >::Transcode(s, eos);
- EXPECT_TRUE(success);
- }
- eos.Flush();
- EXPECT_TRUE(CompareBufferFile(mb.GetBuffer(), mb.GetSize(), expectedFilename));
- }
- }
+ // Test MemoryBuffer
+ {
+ MemoryBuffer mb;
+ AutoUTFOutputStream<unsigned, MemoryBuffer> eos(mb, type, putBOM);
+ StringStream s(json_);
+ while (s.Peek() != '\0') {
+ bool success = Transcoder<UTF8<>, AutoUTF<unsigned> >::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<> >("utf8.json");
- TestEncodedInputStream<UTF8<>, UTF8<> >("utf8bom.json");
- TestEncodedInputStream<UTF16LE<>, UTF16<> >("utf16le.json");
- TestEncodedInputStream<UTF16LE<>, UTF16<> >("utf16lebom.json");
- TestEncodedInputStream<UTF16BE<>, UTF16<> >("utf16be.json");
- TestEncodedInputStream<UTF16BE<>, UTF16<> >("utf16bebom.json");
- TestEncodedInputStream<UTF32LE<>, UTF32<> >("utf32le.json");
- TestEncodedInputStream<UTF32LE<>, UTF32<> >("utf32lebom.json");
- TestEncodedInputStream<UTF32BE<>, UTF32<> >("utf32be.json");
- TestEncodedInputStream<UTF32BE<>, UTF32<> >("utf32bebom.json");
+ TestEncodedInputStream<UTF8<>, UTF8<> >("utf8.json");
+ TestEncodedInputStream<UTF8<>, UTF8<> >("utf8bom.json");
+ TestEncodedInputStream<UTF16LE<>, UTF16<> >("utf16le.json");
+ TestEncodedInputStream<UTF16LE<>, UTF16<> >("utf16lebom.json");
+ TestEncodedInputStream<UTF16BE<>, UTF16<> >("utf16be.json");
+ TestEncodedInputStream<UTF16BE<>, UTF16<> >("utf16bebom.json");
+ TestEncodedInputStream<UTF32LE<>, UTF32<> >("utf32le.json");
+ TestEncodedInputStream<UTF32LE<>, UTF32<> >("utf32lebom.json");
+ TestEncodedInputStream<UTF32BE<>, UTF32<> >("utf32be.json");
+ TestEncodedInputStream<UTF32BE<>, 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<> >("utf8.json", false);
- TestEncodedOutputStream<UTF8<>, UTF8<> >("utf8bom.json", true);
- TestEncodedOutputStream<UTF16LE<>, UTF16<> >("utf16le.json", false);
- TestEncodedOutputStream<UTF16LE<>, UTF16<> >("utf16lebom.json",true);
- TestEncodedOutputStream<UTF16BE<>, UTF16<> >("utf16be.json", false);
- TestEncodedOutputStream<UTF16BE<>, UTF16<> >("utf16bebom.json",true);
- TestEncodedOutputStream<UTF32LE<>, UTF32<> >("utf32le.json", false);
- TestEncodedOutputStream<UTF32LE<>, UTF32<> >("utf32lebom.json",true);
- TestEncodedOutputStream<UTF32BE<>, UTF32<> >("utf32be.json", false);
- TestEncodedOutputStream<UTF32BE<>, UTF32<> >("utf32bebom.json",true);
+ TestEncodedOutputStream<UTF8<>, UTF8<> >("utf8.json", false);
+ TestEncodedOutputStream<UTF8<>, UTF8<> >("utf8bom.json", true);
+ TestEncodedOutputStream<UTF16LE<>, UTF16<> >("utf16le.json", false);
+ TestEncodedOutputStream<UTF16LE<>, UTF16<> >("utf16lebom.json",true);
+ TestEncodedOutputStream<UTF16BE<>, UTF16<> >("utf16be.json", false);
+ TestEncodedOutputStream<UTF16BE<>, UTF16<> >("utf16bebom.json",true);
+ TestEncodedOutputStream<UTF32LE<>, UTF32<> >("utf32le.json", false);
+ TestEncodedOutputStream<UTF32LE<>, UTF32<> >("utf32lebom.json",true);
+ TestEncodedOutputStream<UTF32BE<>, UTF32<> >("utf32be.json", false);
+ TestEncodedOutputStream<UTF32BE<>, 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 86c7d6e7..3beebe64 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 <bjoern@hoehrmann.de>
@@ -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<UTF16<> > os, os2;
- GenericStringBuffer<UTF8<> > 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<UTF16<> > os, os2;
+ GenericStringBuffer<UTF8<> > 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<UTF16<>::Ch>(decodedCodepoint);
- else {
- // Encode code points above U+FFFF as surrogate pair.
- *p++ = static_cast<UTF16<>::Ch>(0xD7C0 + (decodedCodepoint >> 10));
- *p++ = static_cast<UTF16<>::Ch>(0xDC00 + (decodedCodepoint & 0x3FF));
- }
- *p++ = '\0';
+ if (codepoint <= 0xFFFF)
+ *p++ = static_cast<UTF16<>::Ch>(decodedCodepoint);
+ else {
+ // Encode code points above U+FFFF as surrogate pair.
+ *p++ = static_cast<UTF16<>::Ch>(0xD7C0 + (decodedCodepoint >> 10));
+ *p++ = static_cast<UTF16<>::Ch>(0xDC00 + (decodedCodepoint & 0x3FF));
+ }
+ *p++ = '\0';
- EXPECT_EQ(0, StrCmp(buffer, encodedStr));
- }
+ EXPECT_EQ(0, StrCmp(buffer, encodedStr));
+ }
- // Decode
- {
- GenericStringStream<UTF16<> > 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<UTF16<> > 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<UTF16<> > is(encodedStr);
- os2.Clear();
- bool result = UTF16<>::Validate(is, os2);
- EXPECT_TRUE(result);
- EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
- }
- }
- }
+ // Validate
+ {
+ GenericStringStream<UTF16<> > is(encodedStr);
+ os2.Clear();
+ bool result = UTF16<>::Validate(is, os2);
+ EXPECT_TRUE(result);
+ EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
+ }
+ }
+ }
}
TEST(EncodingsTest, UTF32) {
- GenericStringBuffer<UTF32<> > 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<UTF32<> > 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<UTF32<> > 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<UTF32<> > 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<UTF32<> > is(encodedStr);
- os2.Clear();
- bool result = UTF32<>::Validate(is, os2);
- EXPECT_TRUE(result);
- EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
- }
- }
- }
+ // Validate
+ {
+ GenericStringStream<UTF32<> > 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 20a84383..c3217fa2 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_() {}
-
- 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);
- }
-
- virtual void TearDown() {
- free(json_);
- json_ = 0;
- }
+ 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);
+
+ 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;
+ }
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 91e62629..d6615282 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<UTF8<>, 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<UTF8<>, 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<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
- document.Parse((const char*)json);
- EXPECT_TRUE(!document.HasParseError());
- free(json);
- }
+ GenericDocument<UTF8<>, 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 afe0cd7b..e403bb82 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<bool expect>
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<true> h;
- Reader reader;
- reader.ParseTrue<0>(s, h);
- EXPECT_EQ(1u, h.step_);
+ StringStream s("true");
+ ParseBoolHandler<true> h;
+ Reader reader;
+ reader.ParseTrue<0>(s, h);
+ EXPECT_EQ(1u, h.step_);
}
TEST(Reader, ParseFalse) {
- StringStream s("false");
- ParseBoolHandler<false> h;
- Reader reader;
- reader.ParseFalse<0>(s, h);
- EXPECT_EQ(1u, h.step_);
+ StringStream s("false");
+ ParseBoolHandler<false> 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_); \
- }
-
- 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(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_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);
- }
+ { \
+ 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(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(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)
+
+ {
+ 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());\
- }
-
- // 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 exponent in number.
- TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e");
- TEST_NUMBER_ERROR(kParseErrorNumberMissExponent, "1e_");
+ { \
+ 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");
+
+ // 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_");
#undef TEST_NUMBER_ERROR
}
template <typename Encoding>
struct ParseStringHandler : BaseReaderHandler<Encoding> {
- ParseStringHandler() : str_(0), length_(0), copy_() {}
- ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(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<typename Encoding::Ch*>(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_;
+ ParseStringHandler() : str_(0), length_(0), copy_() {}
+ ~ParseStringHandler() { EXPECT_TRUE(str_ != 0); if (copy_) free(const_cast<typename Encoding::Ch*>(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<typename Encoding::Ch*>(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_;
};
TEST(Reader, ParseString) {
#define TEST_STRING(Encoding, e, x) \
- { \
- Encoding::Ch* buffer = StrDup(x); \
- GenericInsituStringStream<Encoding> is(buffer); \
- ParseStringHandler<Encoding> h; \
- GenericReader<Encoding, Encoding> reader; \
- reader.ParseString<kParseInsituFlag | kParseValidateEncodingFlag>(is, h); \
- EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h.str_)); \
- EXPECT_EQ(StrLen(e), h.length_); \
- free(buffer); \
- GenericStringStream<Encoding> s(x); \
- ParseStringHandler<Encoding> h2; \
- GenericReader<Encoding, Encoding> reader2; \
- reader2.ParseString<0>(s, h2); \
- EXPECT_EQ(0, StrCmp<Encoding::Ch>(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.
+ { \
+ Encoding::Ch* buffer = StrDup(x); \
+ GenericInsituStringStream<Encoding> is(buffer); \
+ ParseStringHandler<Encoding> h; \
+ GenericReader<Encoding, Encoding> reader; \
+ reader.ParseString<kParseInsituFlag | kParseValidateEncodingFlag>(is, h); \
+ EXPECT_EQ(0, StrCmp<Encoding::Ch>(e, h.str_)); \
+ EXPECT_EQ(StrLen(e), h.length_); \
+ free(buffer); \
+ GenericStringStream<Encoding> s(x); \
+ ParseStringHandler<Encoding> h2; \
+ GenericReader<Encoding, Encoding> reader2; \
+ reader2.ParseString<0>(s, h2); \
+ EXPECT_EQ(0, StrCmp<Encoding::Ch>(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.
#define ARRAY(...) { __VA_ARGS__ }
#define TEST_STRINGARRAY(Encoding, utype, array, x) \
- { \
- static const utype ue[] = array; \
- static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
- TEST_STRING(Encoding, e, x); \
- }
+ { \
+ static const utype ue[] = array; \
+ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&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<const Encoding::Ch *>(&ue[0]); \
- static const Encoding::Ch* x = reinterpret_cast<const Encoding::Ch *>(&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
-
- // 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
+ { \
+ static const utype ue[] = earray; \
+ static const utype xe[] = xarray; \
+ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
+ static const Encoding::Ch* x = reinterpret_cast<const Encoding::Ch *>(&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
+
+ // 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
#undef TEST_STRINGARRAY
#undef ARRAY
#undef TEST_STRING
- // Support of null character in string
- {
- StringStream s("\"Hello\\u0000World\"");
- const char e[] = "Hello\0World";
- ParseStringHandler<UTF8<> > 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<UTF8<> > 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<UTF8<> > is(x);
- GenericReader<UTF8<>, UTF16<> > reader;
- ParseStringHandler<UTF16<> > h;
- reader.ParseString<0>(is, h);
- EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_));
- EXPECT_EQ(StrLen(e), h.length_);
+ const char* x = "\"Hello\"";
+ const wchar_t* e = L"Hello";
+ GenericStringStream<UTF8<> > is(x);
+ GenericReader<UTF8<>, UTF16<> > reader;
+ ParseStringHandler<UTF16<> > h;
+ reader.ParseString<0>(is, h);
+ EXPECT_EQ(0, StrCmp<UTF16<>::Ch>(e, h.str_));
+ EXPECT_EQ(StrLen(e), h.length_);
}
TEST(Reader, ParseString_NonDestructive) {
- StringStream s("\"Hello\\nWorld\"");
- ParseStringHandler<UTF8<> > 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<UTF8<> > 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<kParseValidateEncodingFlag>(s, h);
- return reader.GetParseErrorCode();
+ StringStream s(str);
+ BaseReaderHandler<> h;
+ Reader reader;
+ reader.Parse<kParseValidateEncodingFlag>(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<const Encoding::Ch *>(&ue[0]); \
- EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\
- }
-
- // Invalid escape character in string.
- TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]");
-
- // 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\"]");
-
- // 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
-
- // 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.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.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.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.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'));
+ { \
+ static const utype ue[] = array; \
+ static const Encoding::Ch* e = reinterpret_cast<const Encoding::Ch *>(&ue[0]); \
+ EXPECT_EQ(kParseErrorStringInvalidEncoding, TestString(e));\
+ }
+
+ // Invalid escape character in string.
+ TEST_STRING_ERROR(kParseErrorStringEscapeInvalid, "[\"\\a\"]");
+
+ // 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\"]");
+
+ // 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
+
+ // 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.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.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.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.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 <unsigned count>
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<>, 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]");
+ { \
+ char buffer[1001]; \
+ strncpy(buffer, str, 1000); \
+ InsituStringStream s(buffer); \
+ BaseReaderHandler<> h; \
+ GenericReader<UTF8<>, 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]");
#undef TEST_ARRAY_ERROR
}
struct ParseObjectHandler : BaseReaderHandler<> {
- 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; }
-
- unsigned step_;
+ 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; }
+
+ 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] } ";
-
- // Insitu
- {
- char* json2 = StrDup(json);
- InsituStringStream s(json2);
- ParseObjectHandler h;
- Reader reader;
- reader.ParseObject<kParseInsituFlag>(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_);
- }
+ 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<kParseInsituFlag>(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_);
+ }
}
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 <unsigned parseFlags>
void TestMultipleRoot() {
- StringStream s("{}[] a");
- ParseMultipleRootHandler h;
- Reader reader;
- EXPECT_TRUE(reader.Parse<parseFlags>(s, h));
- EXPECT_EQ(2u, h.step_);
- EXPECT_TRUE(reader.Parse<parseFlags>(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<parseFlags>(s, h));
+ EXPECT_EQ(2u, h.step_);
+ EXPECT_TRUE(reader.Parse<parseFlags>(s, h));
+ EXPECT_EQ(4u, h.step_);
+ EXPECT_EQ(' ', s.Take());
+ EXPECT_EQ('a', s.Take());
}
TEST(Reader, Parse_MultipleRoot) {
- TestMultipleRoot<kParseStopWhenDoneFlag>();
+ TestMultipleRoot<kParseStopWhenDoneFlag>();
}
TEST(Reader, ParseIterative_MultipleRoot) {
- TestMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
+ TestMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
}
template <unsigned parseFlags>
void TestInsituMultipleRoot() {
- char* buffer = strdup("{}[] a");
- InsituStringStream s(buffer);
- ParseMultipleRootHandler h;
- Reader reader;
- EXPECT_TRUE(reader.Parse<kParseInsituFlag | parseFlags>(s, h));
- EXPECT_EQ(2u, h.step_);
- EXPECT_TRUE(reader.Parse<kParseInsituFlag | parseFlags>(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<kParseInsituFlag | parseFlags>(s, h));
+ EXPECT_EQ(2u, h.step_);
+ EXPECT_TRUE(reader.Parse<kParseInsituFlag | parseFlags>(s, h));
+ EXPECT_EQ(4u, h.step_);
+ EXPECT_EQ(' ', s.Take());
+ EXPECT_EQ('a', s.Take());
+ free(buffer);
}
TEST(Reader, ParseInsitu_MultipleRoot) {
- TestInsituMultipleRoot<kParseStopWhenDoneFlag>();
+ TestInsituMultipleRoot<kParseStopWhenDoneFlag>();
}
TEST(Reader, ParseInsituIterative_MultipleRoot) {
- TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
+ TestInsituMultipleRoot<kParseIterativeFlag | kParseStopWhenDoneFlag>();
}
#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 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 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 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 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]");
+ // 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}");
+
+ // 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 <typename Encoding>
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<size_t>(src_ - head_); }
+ Ch Peek() const { return *src_; }
+ Ch Take() { return *src_++; }
+ size_t Tell() const { return static_cast<size_t>(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 <typename Encoding>
struct StreamTraits<CustomStringStream<Encoding> > {
- 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<UTF8<char> > 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<UTF8<char> > s(json);
+ ParseObjectHandler h;
+ Reader reader;
+ reader.ParseObject<0>(s, h);
+ EXPECT_EQ(20u, h.step_);
}
#include <sstream>
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<char>::eof() ? '\0' : (Ch)c;
- }
+ Ch Peek() const {
+ int c = is_.peek();
+ return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
+ }
- Ch Take() {
- int c = is_.get();
- return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
- }
+ Ch Take() {
+ int c = is_.get();
+ return c == std::char_traits<char>::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<kParseDefaultFlags>(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<kParseDefaultFlags>(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<typename Encoding = UTF8<> >
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;
-
- ParseResult r = reader.IterativeParse<kParseIterativeFlag>(is, handler);
-
- 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
- };
-
- 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;
- }
- }
+ {
+ StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]");
+ Reader reader;
+ IterativeParsingReaderHandler<> handler;
+
+ ParseResult r = reader.IterativeParse<kParseIterativeFlag>(is, handler);
+
+ 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
+ };
+
+ 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;
+ }
+ }
}
TEST(Reader, IterativeParsing_Count) {
- {
- StringStream is("[{}, {\"k\": 1}, [1], []]");
- Reader reader;
- IterativeParsingReaderHandler<> handler;
-
- ParseResult r = reader.IterativeParse<kParseIterativeFlag>(is, handler);
-
- 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
- };
-
- 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;
- }
- }
+ {
+ StringStream is("[{}, {\"k\": 1}, [1], []]");
+ Reader reader;
+ IterativeParsingReaderHandler<> handler;
+
+ ParseResult r = reader.IterativeParse<kParseIterativeFlag>(is, handler);
+
+ 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
+ };
+
+ 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;
+ }
+ }
}
// 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<kParseIterativeFlag>(is, handler);
+ ParseResult r = reader.Parse<kParseIterativeFlag>(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<kParseIterativeFlag>(is, handler);
+ ParseResult r = reader.Parse<kParseIterativeFlag>(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<kParseIterativeFlag>(is, handler);
+ ParseResult r = reader.Parse<kParseIterativeFlag>(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<kParseIterativeFlag>(is, handler);
+ ParseResult r = reader.Parse<kParseIterativeFlag>(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 1b146c33..e92bc66a 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 ad87d720..0330d737 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 <typename Ch>
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<typename Ch>
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 <typename Ch>
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 2aa6379e..fa3b6b8c 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 <algorithm>
@@ -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());
-
- y = 5678;
- EXPECT_TRUE(y.IsInt());
- EXPECT_EQ(5678, y.GetInt());
-
- 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());
-
- static char mstr[] = "mutable";
- // y = mstr; // should not compile
- y = StringRef(mstr);
- EXPECT_TRUE(y.IsString());
- EXPECT_EQ(y.GetString(),mstr);
+ 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());
+
+ 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());
+
+ static char mstr[] = "mutable";
+ // y = mstr; // should not compile
+ y = StringRef(mstr);
+ EXPECT_TRUE(y.IsString());
+ EXPECT_EQ(y.GetString(),mstr);
}
template <typename A, typename B>
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 <typename A, typename B>
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);
-
- // 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);
-
- // 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);
+ 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);
+
+ 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);
+
+ // Swapping member order should be fine.
+ y.RemoveMember("t");
+ TestUnequal(x, y);
+ y.AddMember("t", Value(true).Move(), allocator);
+ TestEqual(x, y);
}
template <typename Value>
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());
-
- 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.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
+ 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.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
}
TEST(Value, CopyFrom) {
- TestCopyFrom<Value>();
- TestCopyFrom<GenericValue<UTF8<>, CrtAllocator> >();
+ TestCopyFrom<Value>();
+ TestCopyFrom<GenericValue<UTF8<>, 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());
-
- 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());
-
- // SetNull();
- Value z(true);
- z.SetNull();
- EXPECT_TRUE(z.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());
+
+ // Constructor with type
+ Value y(kNullType);
+ EXPECT_TRUE(y.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());
-
- 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());
-
- // SetBool()
- Value z;
- z.SetBool(true);
- EXPECT_TRUE(z.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());
+
+ // Constructor with type
+ Value y(kTrueType);
+ EXPECT_TRUE(y.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());
-
- 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());
-
- // SetBool()
- Value z;
- z.SetBool(false);
- EXPECT_TRUE(z.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());
+
+ // Constructor with type
+ Value y(kFalseType);
+ EXPECT_TRUE(y.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());
-
- 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());
-
- // 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());
-
- // operator=(int)
- z = 5678;
- EXPECT_EQ(5678, z.GetInt());
+ // 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());
+
+ 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());
+
+ // SetInt()
+ Value z;
+ z.SetInt(1234);
+ EXPECT_EQ(1234, 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().
-
- 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());
-
- // 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
+ // 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());
+
+ // SetUint()
+ Value z;
+ z.SetUint(1234);
+ EXPECT_EQ(1234u, 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
}
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());
-
- 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());
-
- // 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(4294967296LL); // 2^32, cannot cast as uint
- EXPECT_FALSE(z.IsInt());
- EXPECT_FALSE(z.IsUint());
+ // 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());
+
+ 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());
+
+ 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());
}
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());
-
- 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());
-
- 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(9223372036854775808uLL); // 2^63 cannot cast as int64
- EXPECT_FALSE(z.IsInt64());
-
- // Issue 48
- EXPECT_EQ(9223372036854775808uLL, z.GetUint64());
+ // 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());
+
+ // 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(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());
+
+ // 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());
-
- 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());
-
- z = 56.78;
- EXPECT_EQ(56.78, z.GetDouble());
+ // 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());
+
+ // SetDouble()
+ Value z;
+ z.SetDouble(12.34);
+ EXPECT_EQ(12.34, 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());
-
- 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 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);
-
- 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 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());
-
- 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(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());
+ // 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());
+
+ 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");
+
+ 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");
+
+ // 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());
+
+ // 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(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 = 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());
}
TEST(Value, Array) {
- 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_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);
-
- 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());
-
- // 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());
-
- // Clear()
- x.Clear();
- EXPECT_TRUE(x.Empty());
- EXPECT_EQ(0u, x.Size());
- EXPECT_TRUE(y.Empty());
- EXPECT_EQ(0u, y.Size());
-
- // 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);
-
- // 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());
-
- // 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);
-
- 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.
+ 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_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);
+
+ 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());
+
+ // 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());
+
+ // Clear()
+ x.Clear();
+ EXPECT_TRUE(x.Empty());
+ EXPECT_EQ(0u, x.Size());
+ EXPECT_TRUE(y.Empty());
+ EXPECT_EQ(0u, y.Size());
+
+ // 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);
+
+ // 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());
+
+ // 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);
+
+ 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.
#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);
-
- 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]);
+ // 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]);
#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;
-
- EXPECT_EQ(kObjectType, x.GetType());
- EXPECT_TRUE(x.IsObject());
- EXPECT_EQ(kObjectType, y.GetType());
- EXPECT_TRUE(y.IsObject());
-
- // AddMember()
- x.AddMember("A", "Apple", allocator);
-
- Value value("Banana", 6);
- x.AddMember("B", "Banana", allocator);
-
- // AddMember<T>(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());
- }
-
- // 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"));
-
- 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());
-
- // 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());
-
- // 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"));
-
- x.RemoveMember("B");
- EXPECT_FALSE(x.HasMember("B"));
-
- x.RemoveMember(name);
- EXPECT_FALSE(x.HasMember(name));
-
- EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
-
- // 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);
-
- // 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 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);
-
- 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());
- }
- }
-
- // SetObject()
- Value z;
- z.SetObject();
- EXPECT_TRUE(z.IsObject());
+ 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());
+
+ // AddMember()
+ x.AddMember("A", "Apple", allocator);
+
+ Value value("Banana", 6);
+ x.AddMember("B", "Banana", allocator);
+
+ // AddMember<T>(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());
+ }
+
+ // 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"));
+
+ 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());
+
+ // 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());
+
+ // 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"));
+
+ x.RemoveMember("B");
+ EXPECT_FALSE(x.HasMember("B"));
+
+ x.RemoveMember(name);
+ EXPECT_FALSE(x.HasMember(name));
+
+ EXPECT_TRUE(x.MemberBegin() == x.MemberEnd());
+
+ // 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);
+
+ // 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 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);
+
+ 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());
+ }
+ }
+
+ // SetObject()
+ Value z;
+ z.SetObject();
+ EXPECT_TRUE(z.IsObject());
}
TEST(Value, BigNestedArray) {
- 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++)
- for (SizeType j = 0; j < n; j++) {
- EXPECT_TRUE(x[i][j].IsInt());
- EXPECT_EQ((int)(i * n + j), x[i][j].GetInt());
- }
+ 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++)
+ 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;
-
- 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);
-
- 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);
- }
-
- // 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());
- }
- }
+ MemoryPoolAllocator<> allocator;
+ Value x(kObjectType);
+ static const SizeType n = 200;
+
+ 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);
+
+ 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);
+ }
+
+ // 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());
+ }
+ }
}
// 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<UTF8<>, CrtAllocator> V;
+ typedef GenericValue<UTF8<>, 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 59543b0e..2d83418e 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<StringBuffer> 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<StringBuffer> 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<StringBuffer> writer(buffer); \
- Reader reader; \
- reader.Parse<0>(s, writer); \
- EXPECT_STREQ(json, buffer.GetString()); \
- EXPECT_TRUE(writer.IsComplete()); \
- }
+ { \
+ StringStream s(json); \
+ StringBuffer buffer; \
+ Writer<StringBuffer> 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\"}";
-
- // UTF8 -> UTF16 -> UTF8
- {
- StringStream s(json);
- StringBuffer buffer;
- Writer<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
- GenericReader<UTF8<>, UTF16<> > reader;
- reader.Parse(s, writer);
- EXPECT_STREQ(json, buffer.GetString());
- }
-
- // UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8
- {
- StringStream s(json);
- StringBuffer buffer;
- Writer<StringBuffer, UTF8<>, ASCII<> > writer(buffer);
- Reader reader;
- reader.Parse(s, writer);
-
- StringBuffer buffer2;
- Writer<StringBuffer> writer2(buffer2);
- GenericReader<ASCII<>, UTF8<> > reader2;
- StringStream s2(buffer.GetString());
- reader2.Parse(s2, writer2);
-
- EXPECT_STREQ(json, buffer2.GetString());
- }
+ 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<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
+ GenericReader<UTF8<>, UTF16<> > reader;
+ reader.Parse(s, writer);
+ EXPECT_STREQ(json, buffer.GetString());
+ }
+
+ // UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8
+ {
+ StringStream s(json);
+ StringBuffer buffer;
+ Writer<StringBuffer, UTF8<>, ASCII<> > writer(buffer);
+ Reader reader;
+ reader.Parse(s, writer);
+
+ StringBuffer buffer2;
+ Writer<StringBuffer> writer2(buffer2);
+ GenericReader<ASCII<>, UTF8<> > reader2;
+ StringStream s2(buffer.GetString());
+ reader2.Parse(s2, writer2);
+
+ EXPECT_STREQ(json, buffer2.GetString());
+ }
}
#include <sstream>
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<OStreamWrapper> 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());
+ 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<OStreamWrapper> 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());
}
TEST(Writer, AssertRootMustBeArrayOrObject) {
#define T(x)\
- {\
- StringBuffer buffer;\
- Writer<StringBuffer> 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<StringBuffer> 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<StringBuffer> writer(buffer);
- writer.StartObject();
- writer.EndObject();
- ASSERT_THROW(writer.EndObject(), AssertException);
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.EndObject();
+ ASSERT_THROW(writer.EndObject(), AssertException);
}
TEST(Writer, AssertIncorrectArrayLevel) {
- StringBuffer buffer;
- Writer<StringBuffer> writer(buffer);
- writer.StartArray();
- writer.EndArray();
- ASSERT_THROW(writer.EndArray(), AssertException);
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartArray();
+ writer.EndArray();
+ ASSERT_THROW(writer.EndArray(), AssertException);
}
TEST(Writer, AssertIncorrectEndObject) {
- StringBuffer buffer;
- Writer<StringBuffer> writer(buffer);
- writer.StartObject();
- ASSERT_THROW(writer.EndArray(), AssertException);
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ ASSERT_THROW(writer.EndArray(), AssertException);
}
TEST(Writer, AssertIncorrectEndArray) {
- StringBuffer buffer;
- Writer<StringBuffer> writer(buffer);
- writer.StartObject();
- ASSERT_THROW(writer.EndArray(), AssertException);
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ ASSERT_THROW(writer.EndArray(), AssertException);
}
TEST(Writer, AssertObjectKeyNotString) {
#define T(x)\
- {\
- StringBuffer buffer;\
- Writer<StringBuffer> 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<StringBuffer> 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<StringBuffer> writer(buffer);
- writer.StartObject();
- writer.EndObject();
- ASSERT_THROW(writer.StartObject(), AssertException);
+ StringBuffer buffer;
+ Writer<StringBuffer> writer(buffer);
+ writer.StartObject();
+ writer.EndObject();
+ ASSERT_THROW(writer.StartObject(), AssertException);
}
TEST(Writer, RootObjectIsComplete) {
- StringBuffer buffer;
- Writer<StringBuffer> 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<StringBuffer> 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<StringBuffer> 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<StringBuffer> 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());
}