Add license and change indents from tab to space.
This commit is contained in:
parent
adb3974e4d
commit
0dbcc1cf2e
@ -1,165 +1,165 @@
|
||||
function setTargetObjDir(outDir)
|
||||
for _, cfg in ipairs(configurations()) do
|
||||
for _, plat in ipairs(platforms()) do
|
||||
local action = _ACTION or ""
|
||||
|
||||
local prj = project()
|
||||
|
||||
--"_debug_win32_vs2008"
|
||||
local suffix = "_" .. cfg .. "_" .. plat .. "_" .. action
|
||||
|
||||
targetPath = outDir
|
||||
|
||||
suffix = string.lower(suffix)
|
||||
for _, cfg in ipairs(configurations()) do
|
||||
for _, plat in ipairs(platforms()) do
|
||||
local action = _ACTION or ""
|
||||
|
||||
local prj = project()
|
||||
|
||||
--"_debug_win32_vs2008"
|
||||
local suffix = "_" .. cfg .. "_" .. plat .. "_" .. action
|
||||
|
||||
targetPath = outDir
|
||||
|
||||
suffix = string.lower(suffix)
|
||||
|
||||
local obj_path = "../intermediate/" .. cfg .. "/" .. action .. "/" .. prj.name
|
||||
|
||||
obj_path = string.lower(obj_path)
|
||||
|
||||
configuration {cfg, plat}
|
||||
targetdir(targetPath)
|
||||
objdir(obj_path)
|
||||
targetsuffix(suffix)
|
||||
end
|
||||
end
|
||||
local obj_path = "../intermediate/" .. cfg .. "/" .. action .. "/" .. prj.name
|
||||
|
||||
obj_path = string.lower(obj_path)
|
||||
|
||||
configuration {cfg, plat}
|
||||
targetdir(targetPath)
|
||||
objdir(obj_path)
|
||||
targetsuffix(suffix)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function linkLib(libBaseName)
|
||||
for _, cfg in ipairs(configurations()) do
|
||||
for _, plat in ipairs(platforms()) do
|
||||
local action = _ACTION or ""
|
||||
|
||||
local prj = project()
|
||||
|
||||
local cfgName = cfg
|
||||
|
||||
--"_debug_win32_vs2008"
|
||||
local suffix = "_" .. cfgName .. "_" .. plat .. "_" .. action
|
||||
|
||||
libFullName = libBaseName .. string.lower(suffix)
|
||||
|
||||
configuration {cfg, plat}
|
||||
links(libFullName)
|
||||
end
|
||||
end
|
||||
for _, cfg in ipairs(configurations()) do
|
||||
for _, plat in ipairs(platforms()) do
|
||||
local action = _ACTION or ""
|
||||
|
||||
local prj = project()
|
||||
|
||||
local cfgName = cfg
|
||||
|
||||
--"_debug_win32_vs2008"
|
||||
local suffix = "_" .. cfgName .. "_" .. plat .. "_" .. action
|
||||
|
||||
libFullName = libBaseName .. string.lower(suffix)
|
||||
|
||||
configuration {cfg, plat}
|
||||
links(libFullName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
solution "test"
|
||||
configurations { "debug", "release" }
|
||||
platforms { "x32", "x64" }
|
||||
configurations { "debug", "release" }
|
||||
platforms { "x32", "x64" }
|
||||
|
||||
location ("./" .. (_ACTION or ""))
|
||||
language "C++"
|
||||
flags { "ExtraWarnings" }
|
||||
|
||||
configuration "debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols" }
|
||||
location ("./" .. (_ACTION or ""))
|
||||
language "C++"
|
||||
flags { "ExtraWarnings" }
|
||||
|
||||
configuration "debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols" }
|
||||
|
||||
configuration "release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize" }
|
||||
configuration "release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize" }
|
||||
|
||||
configuration "vs*"
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
|
||||
configuration "gmake"
|
||||
buildoptions "-msse4.2 -Wall -Wextra"
|
||||
configuration "vs*"
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
|
||||
configuration "gmake"
|
||||
buildoptions "-msse4.2 -Wall -Wextra"
|
||||
|
||||
project "gtest"
|
||||
kind "StaticLib"
|
||||
|
||||
defines { "GTEST_HAS_PTHREAD=0" }
|
||||
project "gtest"
|
||||
kind "StaticLib"
|
||||
|
||||
defines { "GTEST_HAS_PTHREAD=0" }
|
||||
|
||||
files {
|
||||
"../thirdparty/gtest/src/gtest-all.cc",
|
||||
"../thirdparty/gtest/src/**.h",
|
||||
}
|
||||
files {
|
||||
"../thirdparty/gtest/src/gtest-all.cc",
|
||||
"../thirdparty/gtest/src/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../thirdparty/gtest/",
|
||||
"../thirdparty/gtest/include",
|
||||
}
|
||||
includedirs {
|
||||
"../thirdparty/gtest/",
|
||||
"../thirdparty/gtest/include",
|
||||
}
|
||||
|
||||
setTargetObjDir("../thirdparty/lib")
|
||||
setTargetObjDir("../thirdparty/lib")
|
||||
|
||||
project "unittest"
|
||||
kind "ConsoleApp"
|
||||
|
||||
if _ACTION == "gmake" then
|
||||
buildoptions "-Werror -Weffc++ -Wswitch-default"
|
||||
end
|
||||
project "unittest"
|
||||
kind "ConsoleApp"
|
||||
|
||||
if _ACTION == "gmake" then
|
||||
buildoptions "-Werror -Weffc++ -Wswitch-default"
|
||||
end
|
||||
|
||||
files {
|
||||
"../include/**.h",
|
||||
"../test/unittest/**.cpp",
|
||||
"../test/unittest/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../include/",
|
||||
"../thirdparty/gtest/include/",
|
||||
}
|
||||
files {
|
||||
"../include/**.h",
|
||||
"../test/unittest/**.cpp",
|
||||
"../test/unittest/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../include/",
|
||||
"../thirdparty/gtest/include/",
|
||||
}
|
||||
|
||||
libdirs "../thirdparty/lib"
|
||||
libdirs "../thirdparty/lib"
|
||||
|
||||
setTargetObjDir("../bin")
|
||||
setTargetObjDir("../bin")
|
||||
|
||||
linkLib "gtest"
|
||||
links "gtest"
|
||||
|
||||
project "perftest"
|
||||
kind "ConsoleApp"
|
||||
|
||||
files {
|
||||
"../include/**.h",
|
||||
"../test/perftest/**.cpp",
|
||||
"../test/perftest/**.c",
|
||||
"../test/perftest/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../include/",
|
||||
"../thirdparty/gtest/include/",
|
||||
"../thirdparty/",
|
||||
"../thirdparty/jsoncpp/include/",
|
||||
"../thirdparty/libjson/",
|
||||
"../thirdparty/yajl/include/",
|
||||
}
|
||||
linkLib "gtest"
|
||||
links "gtest"
|
||||
|
||||
project "perftest"
|
||||
kind "ConsoleApp"
|
||||
|
||||
files {
|
||||
"../include/**.h",
|
||||
"../test/perftest/**.cpp",
|
||||
"../test/perftest/**.c",
|
||||
"../test/perftest/**.h",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"../include/",
|
||||
"../thirdparty/gtest/include/",
|
||||
"../thirdparty/",
|
||||
"../thirdparty/jsoncpp/include/",
|
||||
"../thirdparty/libjson/",
|
||||
"../thirdparty/yajl/include/",
|
||||
}
|
||||
|
||||
libdirs "../thirdparty/lib"
|
||||
libdirs "../thirdparty/lib"
|
||||
|
||||
setTargetObjDir("../bin")
|
||||
setTargetObjDir("../bin")
|
||||
|
||||
linkLib "gtest"
|
||||
links "gtest"
|
||||
linkLib "gtest"
|
||||
links "gtest"
|
||||
|
||||
solution "example"
|
||||
configurations { "debug", "release" }
|
||||
platforms { "x32", "x64" }
|
||||
location ("./" .. (_ACTION or ""))
|
||||
language "C++"
|
||||
flags { "ExtraWarnings" }
|
||||
includedirs "../include/"
|
||||
configurations { "debug", "release" }
|
||||
platforms { "x32", "x64" }
|
||||
location ("./" .. (_ACTION or ""))
|
||||
language "C++"
|
||||
flags { "ExtraWarnings" }
|
||||
includedirs "../include/"
|
||||
|
||||
configuration "debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols" }
|
||||
configuration "debug"
|
||||
defines { "DEBUG" }
|
||||
flags { "Symbols" }
|
||||
|
||||
configuration "release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize", "EnableSSE2" }
|
||||
configuration "release"
|
||||
defines { "NDEBUG" }
|
||||
flags { "Optimize", "EnableSSE2" }
|
||||
|
||||
configuration "vs*"
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
configuration "vs*"
|
||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||
|
||||
configuration "gmake"
|
||||
buildoptions "-Werror -Wall -Wextra -Weffc++ -Wswitch-default"
|
||||
configuration "gmake"
|
||||
buildoptions "-Werror -Wall -Wextra -Weffc++ -Wswitch-default"
|
||||
|
||||
local examplepaths = os.matchdirs("../example/*")
|
||||
for _, examplepath in ipairs(examplepaths) do
|
||||
project(path.getname(examplepath))
|
||||
kind "ConsoleApp"
|
||||
files(examplepath .. "/*")
|
||||
setTargetObjDir("../bin")
|
||||
end
|
||||
local examplepaths = os.matchdirs("../example/*")
|
||||
for _, examplepath in ipairs(examplepaths) do
|
||||
project(path.getname(examplepath))
|
||||
kind "ConsoleApp"
|
||||
files(examplepath .. "/*")
|
||||
setTargetObjDir("../bin")
|
||||
end
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -31,5 +31,5 @@ int main() {
|
||||
|
||||
cout << s.GetString() << endl;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -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");
|
||||
printf("\nParsing to document succeeded.\n");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 2. Access values in document.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 2. Access values in document.
|
||||
|
||||
printf("\nAccess values in document:\n");
|
||||
assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
|
||||
printf("\nAccess values in document:\n");
|
||||
assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
|
||||
|
||||
assert(document.HasMember("hello"));
|
||||
assert(document["hello"].IsString());
|
||||
printf("hello = %s\n", document["hello"].GetString());
|
||||
assert(document.HasMember("hello"));
|
||||
assert(document["hello"].IsString());
|
||||
printf("hello = %s\n", document["hello"].GetString());
|
||||
|
||||
// Since version 0.2, you can use single lookup to check the existing of member and its value:
|
||||
Value::MemberIterator hello = document.FindMember("hello");
|
||||
assert(hello != document.MemberEnd());
|
||||
assert(hello->value.IsString());
|
||||
assert(strcmp("world", hello->value.GetString()) == 0);
|
||||
(void)hello;
|
||||
// Since version 0.2, you can use single lookup to check the existing of member and its value:
|
||||
Value::MemberIterator hello = document.FindMember("hello");
|
||||
assert(hello != document.MemberEnd());
|
||||
assert(hello->value.IsString());
|
||||
assert(strcmp("world", hello->value.GetString()) == 0);
|
||||
(void)hello;
|
||||
|
||||
assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
|
||||
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
|
||||
assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
|
||||
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
|
||||
|
||||
assert(document["f"].IsBool());
|
||||
printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
|
||||
assert(document["f"].IsBool());
|
||||
printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
|
||||
|
||||
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
|
||||
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
|
||||
|
||||
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
|
||||
assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
|
||||
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
|
||||
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
|
||||
assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
|
||||
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
|
||||
|
||||
assert(document["pi"].IsNumber());
|
||||
assert(document["pi"].IsDouble());
|
||||
printf("pi = %g\n", document["pi"].GetDouble());
|
||||
assert(document["pi"].IsNumber());
|
||||
assert(document["pi"].IsDouble());
|
||||
printf("pi = %g\n", document["pi"].GetDouble());
|
||||
|
||||
{
|
||||
const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
|
||||
assert(a.IsArray());
|
||||
for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
|
||||
printf("a[%d] = %d\n", i, a[i].GetInt());
|
||||
|
||||
// Note:
|
||||
//int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
|
||||
int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
|
||||
int z = a[0u].GetInt(); // This works too.
|
||||
(void)y;
|
||||
(void)z;
|
||||
{
|
||||
const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
|
||||
assert(a.IsArray());
|
||||
for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
|
||||
printf("a[%d] = %d\n", i, a[i].GetInt());
|
||||
|
||||
// Note:
|
||||
//int x = a[0].GetInt(); // Error: operator[ is ambiguous, as 0 also mean a null pointer of const char* type.
|
||||
int y = a[SizeType(0)].GetInt(); // Cast to SizeType will work.
|
||||
int z = a[0u].GetInt(); // This works too.
|
||||
(void)y;
|
||||
(void)z;
|
||||
|
||||
// Iterating array with iterators
|
||||
printf("a = ");
|
||||
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
|
||||
printf("%d ", itr->GetInt());
|
||||
printf("\n");
|
||||
}
|
||||
// Iterating array with iterators
|
||||
printf("a = ");
|
||||
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
|
||||
printf("%d ", itr->GetInt());
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Iterating object members
|
||||
static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
|
||||
for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
|
||||
printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]);
|
||||
// Iterating object members
|
||||
static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
|
||||
for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
|
||||
printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 3. Modify values in document.
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 3. Modify values in document.
|
||||
|
||||
// Change i to a bigger number
|
||||
{
|
||||
uint64_t f20 = 1; // compute factorial of 20
|
||||
for (uint64_t j = 1; j <= 20; j++)
|
||||
f20 *= j;
|
||||
document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
|
||||
assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
|
||||
}
|
||||
// Change i to a bigger number
|
||||
{
|
||||
uint64_t f20 = 1; // compute factorial of 20
|
||||
for (uint64_t j = 1; j <= 20; j++)
|
||||
f20 *= j;
|
||||
document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
|
||||
assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
|
||||
}
|
||||
|
||||
// Adding values to array.
|
||||
{
|
||||
Value& a = document["a"]; // This time we uses non-const reference.
|
||||
Document::AllocatorType& allocator = document.GetAllocator();
|
||||
for (int i = 5; i <= 10; i++)
|
||||
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
|
||||
// Adding values to array.
|
||||
{
|
||||
Value& a = document["a"]; // This time we uses non-const reference.
|
||||
Document::AllocatorType& allocator = document.GetAllocator();
|
||||
for (int i = 5; i <= 10; i++)
|
||||
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
|
||||
|
||||
// Fluent API
|
||||
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
|
||||
}
|
||||
// Fluent API
|
||||
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
|
||||
}
|
||||
|
||||
// Making string values.
|
||||
// Making string values.
|
||||
|
||||
// This version of SetString() just store the pointer to the string.
|
||||
// So it is for literal and string that exists within value's life-cycle.
|
||||
{
|
||||
document["hello"] = "rapidjson"; // This will invoke strlen()
|
||||
// Faster version:
|
||||
// document["hello"].SetString("rapidjson", 9);
|
||||
}
|
||||
// This version of SetString() just store the pointer to the string.
|
||||
// So it is for literal and string that exists within value's life-cycle.
|
||||
{
|
||||
document["hello"] = "rapidjson"; // This will invoke strlen()
|
||||
// Faster version:
|
||||
// document["hello"].SetString("rapidjson", 9);
|
||||
}
|
||||
|
||||
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
|
||||
Value author;
|
||||
{
|
||||
char buffer[10];
|
||||
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
||||
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
|
||||
Value author;
|
||||
{
|
||||
char buffer[10];
|
||||
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
||||
|
||||
author.SetString(buffer, static_cast<size_t>(len), document.GetAllocator());
|
||||
// Shorter but slower version:
|
||||
// document["hello"].SetString(buffer, document.GetAllocator());
|
||||
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());
|
||||
// Constructor version:
|
||||
// Value author(buffer, len, document.GetAllocator());
|
||||
// Value author(buffer, document.GetAllocator());
|
||||
memset(buffer, 0, sizeof(buffer)); // For demonstration purpose.
|
||||
}
|
||||
// Variable 'buffer' is unusable now but 'author' has already made a copy.
|
||||
document.AddMember("author", author, document.GetAllocator());
|
||||
|
||||
assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
|
||||
assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 4. Stringify JSON
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 4. Stringify JSON
|
||||
|
||||
printf("\nModified JSON with reformatting:\n");
|
||||
FileStream f(stdout);
|
||||
PrettyWriter<FileStream> writer(f);
|
||||
document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,3 +1,23 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
@ -9,31 +29,31 @@ namespace rapidjson {
|
||||
// Allocator
|
||||
|
||||
/*! \class rapidjson::Allocator
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
\brief Concept for allocating, resizing and freeing memory block.
|
||||
|
||||
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||
|
||||
So if an allocator need to support Free(), it needs to put its pointer in
|
||||
the header of memory block.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
@ -43,14 +63,14 @@ concept Allocator {
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\note implements Allocator concept
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) { return malloc(size); }
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
|
||||
static void Free(void *ptr) { free(ptr); }
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) { return malloc(size); }
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return realloc(originalPtr, newSize); }
|
||||
static void Free(void *ptr) { free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -70,155 +90,155 @@ public:
|
||||
The user-buffer is not deallocated by this allocator.
|
||||
|
||||
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||
\note implements Allocator concept
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
|
||||
AddChunk(chunk_capacity_);
|
||||
}
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = new BaseAllocator();
|
||||
AddChunk(chunk_capacity_);
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<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_;
|
||||
}
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
delete ownBaseAllocator_;
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
}
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
|
||||
chunkHead_->size += size;
|
||||
return buffer;
|
||||
}
|
||||
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);
|
||||
//! Resizes a memory block (concept Allocator)
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
if (originalPtr == 0)
|
||||
return Malloc(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
increment = RAPIDJSON_ALIGN(increment);
|
||||
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||
chunkHead_->size += increment;
|
||||
return originalPtr;
|
||||
}
|
||||
}
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<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);
|
||||
}
|
||||
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||
void* newBuffer = Malloc(newSize);
|
||||
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
||||
return memcpy(newBuffer, originalPtr, originalSize);
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
}
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
ChunkHeader* chunk = reinterpret_cast<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.
|
||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = (const unsigned char *)is_->Peek4();
|
||||
if (!c)
|
||||
return;
|
||||
const unsigned char* c = (const unsigned char *)is_->Peek4();
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
|
||||
if (!hasBOM_) {
|
||||
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
if (!hasBOM_) {
|
||||
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
switch (type_) {
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid type
|
||||
}
|
||||
}
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
switch (type_) {
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid type
|
||||
}
|
||||
}
|
||||
|
||||
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||
InputByteStream* is_;
|
||||
UTFType type_;
|
||||
Ch current_;
|
||||
TakeFunc takeFunc_;
|
||||
bool hasBOM_;
|
||||
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||
InputByteStream* is_;
|
||||
UTFType type_;
|
||||
Ch current_;
|
||||
TakeFunc takeFunc_;
|
||||
bool hasBOM_;
|
||||
};
|
||||
|
||||
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||
/*!
|
||||
\tparam CharType Type of character for writing.
|
||||
\tparam InputByteStream type of output byte stream to be wrapped.
|
||||
\tparam CharType Type of character for writing.
|
||||
\tparam InputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <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;
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
switch (type_) {
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid UTFType
|
||||
}
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
// RUntime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
switch (type_) {
|
||||
case kUTF16LE:
|
||||
case kUTF16BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
break;
|
||||
case kUTF32LE:
|
||||
case kUTF32BE:
|
||||
RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
break;
|
||||
case kUTF8:
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
RAPIDJSON_ASSERT(false); // Invalid UTFType
|
||||
}
|
||||
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
UTFType GetType() const { return type_; }
|
||||
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); }
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
};
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,23 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef RAPIDJSON_ERROR_EN_H__
|
||||
#define RAPIDJSON_ERROR_EN_H__
|
||||
|
||||
@ -7,43 +27,43 @@ namespace rapidjson {
|
||||
|
||||
//! Maps error code of parsing into error message.
|
||||
/*!
|
||||
\param parseErrorCode Error code obtained in parsing.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
\param parseErrorCode Error code obtained in parsing.
|
||||
\return the error message.
|
||||
\note User can make a copy of this function for localization.
|
||||
Using switch-case is safer for future modification of error codes.
|
||||
*/
|
||||
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||
switch (parseErrorCode) {
|
||||
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||
switch (parseErrorCode) {
|
||||
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||
|
||||
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||
case kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array.");
|
||||
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
|
||||
|
||||
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||
|
||||
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||
|
||||
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||
case kParseErrorDocumentRootNotObjectOrArray: return RAPIDJSON_ERROR_STRING("The document root must be either object or array.");
|
||||
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
|
||||
|
||||
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||
|
||||
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||
|
||||
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||
|
||||
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||
|
||||
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||
|
||||
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||
|
||||
default:
|
||||
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
default:
|
||||
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
@ -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
|
||||
*/
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,23 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef RAPIDJSON_FILESTREAM_H_
|
||||
#define RAPIDJSON_FILESTREAM_H_
|
||||
|
||||
@ -8,44 +28,44 @@ namespace rapidjson {
|
||||
|
||||
//! (Depreciated) Wrapper of C file stream for input or output.
|
||||
/*!
|
||||
This simple wrapper does not check the validity of the stream.
|
||||
\note implements Stream concept
|
||||
\note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.
|
||||
This simple wrapper does not check the validity of the stream.
|
||||
\note implements Stream concept
|
||||
\note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.
|
||||
*/
|
||||
class FileStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileStream(FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }
|
||||
char Peek() const { return current_; }
|
||||
char Take() { char c = current_; Read(); return c; }
|
||||
size_t Tell() const { return count_; }
|
||||
void Put(char c) { fputc(c, fp_); }
|
||||
void Flush() { fflush(fp_); }
|
||||
FileStream(FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }
|
||||
char Peek() const { return current_; }
|
||||
char Take() { char c = current_; Read(); return c; }
|
||||
size_t Tell() const { return count_; }
|
||||
void Put(char c) { fputc(c, fp_); }
|
||||
void Flush() { fflush(fp_); }
|
||||
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileStream(const FileStream&);
|
||||
FileStream& operator=(const FileStream&);
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileStream(const FileStream&);
|
||||
FileStream& operator=(const FileStream&);
|
||||
|
||||
void Read() {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
int c = fgetc(fp_);
|
||||
if (c != EOF) {
|
||||
current_ = (char)c;
|
||||
count_++;
|
||||
}
|
||||
else if (current_ != '\0')
|
||||
current_ = '\0';
|
||||
}
|
||||
void Read() {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
int c = fgetc(fp_);
|
||||
if (c != EOF) {
|
||||
current_ = (char)c;
|
||||
count_++;
|
||||
}
|
||||
else if (current_ != '\0')
|
||||
current_ = '\0';
|
||||
}
|
||||
|
||||
FILE* fp_;
|
||||
char current_;
|
||||
size_t count_;
|
||||
FILE* fp_;
|
||||
char current_;
|
||||
size_t count_;
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
@ -1,3 +1,23 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
@ -8,68 +28,68 @@ namespace rapidjson {
|
||||
|
||||
//! Wrapper of C file stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
FileWriteStream(FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
|
||||
*current_++ = c;
|
||||
}
|
||||
*current_++ = c;
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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_;
|
||||
}
|
||||
}
|
||||
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; }
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
|
||||
FILE* fp_;
|
||||
char *buffer_;
|
||||
char *bufferEnd_;
|
||||
char *current_;
|
||||
FILE* fp_;
|
||||
char *buffer_;
|
||||
char *bufferEnd_;
|
||||
char *current_;
|
||||
};
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||
stream.PutN(c, n);
|
||||
stream.PutN(c, n);
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
@ -1,5 +1,26 @@
|
||||
// Modified from https://github.com/miloyip/dtoa-benchmark/blob/master/src/milo/dtoa_milo.h
|
||||
// API is changed to return the character passed the end of string, without writing '\0'
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||
|
||||
#ifndef RAPIDJSON_DTOA_
|
||||
#define RAPIDJSON_DTOA_
|
||||
@ -22,385 +43,369 @@ RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
struct DiyFp {
|
||||
DiyFp() {}
|
||||
DiyFp() {}
|
||||
|
||||
DiyFp(uint64_t f, int e) : f(f), e(e) {}
|
||||
DiyFp(uint64_t f, int e) : f(f), e(e) {}
|
||||
|
||||
DiyFp(double d) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u = { d };
|
||||
DiyFp(double d) {
|
||||
union {
|
||||
double d;
|
||||
uint64_t u64;
|
||||
} u = { d };
|
||||
|
||||
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
|
||||
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||
if (biased_e != 0) {
|
||||
f = significand + kDpHiddenBit;
|
||||
e = biased_e - kDpExponentBias;
|
||||
}
|
||||
else {
|
||||
f = significand;
|
||||
e = kDpMinExponent + 1;
|
||||
}
|
||||
}
|
||||
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
|
||||
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||
if (biased_e != 0) {
|
||||
f = significand + kDpHiddenBit;
|
||||
e = biased_e - kDpExponentBias;
|
||||
}
|
||||
else {
|
||||
f = significand;
|
||||
e = kDpMinExponent + 1;
|
||||
}
|
||||
}
|
||||
|
||||
DiyFp operator-(const DiyFp& rhs) const {
|
||||
return DiyFp(f - rhs.f, e);
|
||||
}
|
||||
DiyFp operator-(const DiyFp& rhs) const {
|
||||
return DiyFp(f - rhs.f, e);
|
||||
}
|
||||
|
||||
DiyFp operator*(const DiyFp& rhs) const {
|
||||
DiyFp operator*(const DiyFp& rhs) const {
|
||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||
uint64_t h;
|
||||
uint64_t l = _umul128(f, rhs.f, &h);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
uint64_t h;
|
||||
uint64_t l = _umul128(f, rhs.f, &h);
|
||||
if (l & (uint64_t(1) << 63)) // rounding
|
||||
h++;
|
||||
return DiyFp(h, e + rhs.e + 64);
|
||||
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||
unsigned __int128 p = static_cast<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;
|
||||
}
|
||||
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
|
||||
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||
mi.f <<= mi.e - pl.e;
|
||||
mi.e = pl.e;
|
||||
*plus = pl;
|
||||
*minus = mi;
|
||||
}
|
||||
|
||||
static const int kDiySignificandSize = 64;
|
||||
static const int kDpSignificandSize = 52;
|
||||
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||
static const int kDpMinExponent = -kDpExponentBias;
|
||||
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
static const int kDiySignificandSize = 64;
|
||||
static const int kDpSignificandSize = 52;
|
||||
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||
static const int kDpMinExponent = -kDpExponentBias;
|
||||
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
uint64_t f;
|
||||
int e;
|
||||
uint64_t f;
|
||||
int e;
|
||||
};
|
||||
|
||||
inline DiyFp GetCachedPower(int e, int* K) {
|
||||
// 10^-348, 10^-340, ..., 10^340
|
||||
static const uint64_t kCachedPowers_F[] = {
|
||||
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||
};
|
||||
static const int16_t kCachedPowers_E[] = {
|
||||
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||
907, 933, 960, 986, 1013, 1039, 1066
|
||||
};
|
||||
// 10^-348, 10^-340, ..., 10^340
|
||||
static const uint64_t kCachedPowers_F[] = {
|
||||
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||
};
|
||||
static const int16_t kCachedPowers_E[] = {
|
||||
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||
907, 933, 960, 986, 1013, 1039, 1066
|
||||
};
|
||||
|
||||
//int k = static_cast<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++;
|
||||
//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
|
||||
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]);
|
||||
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;
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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 v(value);
|
||||
DiyFp w_m, w_p;
|
||||
v.NormalizedBoundaries(&w_m, &w_p);
|
||||
|
||||
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||
const DiyFp W = v.Normalize() * c_mk;
|
||||
DiyFp Wp = w_p * c_mk;
|
||||
DiyFp Wm = w_m * c_mk;
|
||||
Wm.f++;
|
||||
Wp.f--;
|
||||
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||
const DiyFp W = v.Normalize() * c_mk;
|
||||
DiyFp Wp = w_p * c_mk;
|
||||
DiyFp Wm = w_m * c_mk;
|
||||
Wm.f++;
|
||||
Wp.f--;
|
||||
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||
}
|
||||
|
||||
//inline const char* GetDigitsLut() {
|
||||
// static const char cDigitsLut[200] = {
|
||||
// '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
|
||||
// '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
|
||||
// '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
|
||||
// '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
|
||||
// '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
|
||||
// '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
|
||||
// '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
|
||||
// '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
|
||||
// '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
|
||||
// '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
|
||||
// };
|
||||
// return cDigitsLut;
|
||||
//}
|
||||
|
||||
inline char* WriteExponent(int K, char* buffer) {
|
||||
if (K < 0) {
|
||||
*buffer++ = '-';
|
||||
K = -K;
|
||||
}
|
||||
if (K < 0) {
|
||||
*buffer++ = '-';
|
||||
K = -K;
|
||||
}
|
||||
|
||||
if (K >= 100) {
|
||||
*buffer++ = '0' + static_cast<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);
|
||||
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;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline char* Prettify(char* buffer, int length, int k) {
|
||||
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||
|
||||
if (length <= kk && kk <= 21) {
|
||||
// 1234e7 -> 12340000000
|
||||
for (int i = length; i < kk; i++)
|
||||
buffer[i] = '0';
|
||||
buffer[kk] = '.';
|
||||
buffer[kk + 1] = '0';
|
||||
return &buffer[kk + 2];
|
||||
}
|
||||
else if (0 < kk && kk <= 21) {
|
||||
// 1234e-2 -> 12.34
|
||||
memmove(&buffer[kk + 1], &buffer[kk], length - kk);
|
||||
buffer[kk] = '.';
|
||||
return &buffer[length + 1];
|
||||
}
|
||||
else if (-6 < kk && kk <= 0) {
|
||||
// 1234e-6 -> 0.001234
|
||||
const int offset = 2 - kk;
|
||||
memmove(&buffer[offset], &buffer[0], length);
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
for (int i = 2; i < offset; i++)
|
||||
buffer[i] = '0';
|
||||
return &buffer[length + offset];
|
||||
}
|
||||
else if (length == 1) {
|
||||
// 1e30
|
||||
buffer[1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[2]);
|
||||
}
|
||||
else {
|
||||
// 1234e30 -> 1.234e33
|
||||
memmove(&buffer[2], &buffer[1], length - 1);
|
||||
buffer[1] = '.';
|
||||
buffer[length + 1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||
}
|
||||
if (length <= kk && kk <= 21) {
|
||||
// 1234e7 -> 12340000000
|
||||
for (int i = length; i < kk; i++)
|
||||
buffer[i] = '0';
|
||||
buffer[kk] = '.';
|
||||
buffer[kk + 1] = '0';
|
||||
return &buffer[kk + 2];
|
||||
}
|
||||
else if (0 < kk && kk <= 21) {
|
||||
// 1234e-2 -> 12.34
|
||||
memmove(&buffer[kk + 1], &buffer[kk], length - kk);
|
||||
buffer[kk] = '.';
|
||||
return &buffer[length + 1];
|
||||
}
|
||||
else if (-6 < kk && kk <= 0) {
|
||||
// 1234e-6 -> 0.001234
|
||||
const int offset = 2 - kk;
|
||||
memmove(&buffer[offset], &buffer[0], length);
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
for (int i = 2; i < offset; i++)
|
||||
buffer[i] = '0';
|
||||
return &buffer[length + offset];
|
||||
}
|
||||
else if (length == 1) {
|
||||
// 1e30
|
||||
buffer[1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[2]);
|
||||
}
|
||||
else {
|
||||
// 1234e30 -> 1.234e33
|
||||
memmove(&buffer[2], &buffer[1], length - 1);
|
||||
buffer[1] = '.';
|
||||
buffer[length + 1] = 'e';
|
||||
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
inline char* dtoa(double value, char* buffer) {
|
||||
if (value == 0) {
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else {
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
value = -value;
|
||||
}
|
||||
int length, K;
|
||||
Grisu2(value, buffer, &length, &K);
|
||||
return Prettify(buffer, length, K);
|
||||
}
|
||||
if (value == 0) {
|
||||
buffer[0] = '0';
|
||||
buffer[1] = '.';
|
||||
buffer[2] = '0';
|
||||
return &buffer[3];
|
||||
}
|
||||
else {
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
value = -value;
|
||||
}
|
||||
int length, K;
|
||||
Grisu2(value, buffer, &length, &K);
|
||||
return Prettify(buffer, length, K);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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* allocator, size_t stack_capacity) : allocator_(allocator), own_allocator_(0), stack_(0), stack_top_(0), stack_end_(0), stack_capacity_(stack_capacity) {
|
||||
RAPIDJSON_ASSERT(stack_capacity_ > 0);
|
||||
if (!allocator_)
|
||||
own_allocator_ = allocator_ = new Allocator();
|
||||
stack_top_ = stack_ = (char*)allocator_->Malloc(stack_capacity_);
|
||||
stack_end_ = stack_ + stack_capacity_;
|
||||
}
|
||||
|
||||
~Stack() {
|
||||
Allocator::Free(stack_);
|
||||
delete own_allocator_; // Only delete if it is owned by the stack
|
||||
}
|
||||
~Stack() {
|
||||
Allocator::Free(stack_);
|
||||
delete own_allocator_; // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
|
||||
void Clear() { /*stack_top_ = 0;*/ stack_top_ = stack_; }
|
||||
|
||||
// Optimization note: try to minimize the size of this function for force inline.
|
||||
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||
template<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);
|
||||
// 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;
|
||||
}
|
||||
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* 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* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stack_top_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return (T*)stack_; }
|
||||
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_; }
|
||||
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_;
|
||||
}
|
||||
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&);
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* own_allocator_;
|
||||
char *stack_;
|
||||
char *stack_top_;
|
||||
char *stack_end_;
|
||||
size_t stack_capacity_;
|
||||
Allocator* allocator_;
|
||||
Allocator* own_allocator_;
|
||||
char *stack_;
|
||||
char *stack_top_;
|
||||
char *stack_end_;
|
||||
size_t stack_capacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
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) {}
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
PrettyWriter(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
//! Set custom indentation.
|
||||
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||
\param indentCharCount Number of indent characters for each indentation level.
|
||||
\note The default indentation is 4 spaces.
|
||||
*/
|
||||
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||
indentChar_ = indentChar;
|
||||
indentCharCount_ = indentCharCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! @name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
/*! @name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
|
||||
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
|
||||
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
|
||||
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
|
||||
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
|
||||
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
|
||||
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
|
||||
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
|
||||
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
|
||||
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
return Base::WriteString(str, length);
|
||||
}
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
PrettyPrefix(kStringType);
|
||||
return Base::WriteString(str, length);
|
||||
}
|
||||
|
||||
bool StartObject() {
|
||||
PrettyPrefix(kObjectType);
|
||||
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||
return Base::WriteStartObject();
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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 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;
|
||||
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;
|
||||
}
|
||||
if (!empty) {
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
if (!Base::WriteEndArray())
|
||||
return false;
|
||||
if (Base::level_stack_.Empty()) // end of json text
|
||||
Base::os_->Flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
//@}
|
||||
//@}
|
||||
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
//@}
|
||||
protected:
|
||||
void PrettyPrefix(Type type) {
|
||||
(void)type;
|
||||
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||
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->inArray) {
|
||||
if (level->valueCount > 0) {
|
||||
Base::os_->Put(','); // add comma if it is not the first element in array
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else
|
||||
Base::os_->Put('\n');
|
||||
WriteIndent();
|
||||
}
|
||||
else { // in object
|
||||
if (level->valueCount > 0) {
|
||||
if (level->valueCount % 2 == 0) {
|
||||
Base::os_->Put(',');
|
||||
Base::os_->Put('\n');
|
||||
}
|
||||
else {
|
||||
Base::os_->Put(':');
|
||||
Base::os_->Put(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
Base::os_->Put('\n');
|
||||
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
|
||||
Base::hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
if (level->valueCount % 2 == 0)
|
||||
WriteIndent();
|
||||
}
|
||||
if (!level->inArray && level->valueCount % 2 == 0)
|
||||
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||
level->valueCount++;
|
||||
}
|
||||
else {
|
||||
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
|
||||
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
|
||||
Base::hasRoot_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(*Base::os_, indentChar_, count);
|
||||
}
|
||||
void WriteIndent() {
|
||||
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||
PutN(*Base::os_, indentChar_, count);
|
||||
}
|
||||
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
Ch indentChar_;
|
||||
unsigned indentCharCount_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
PrettyWriter(const PrettyWriter&);
|
||||
PrettyWriter& operator=(const PrettyWriter&);
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
PrettyWriter(const PrettyWriter&);
|
||||
PrettyWriter& operator=(const PrettyWriter&);
|
||||
};
|
||||
|
||||
} // namespace rapidjson
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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;
|
||||
typedef typename SourceEncoding::Ch Ch;
|
||||
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
|
||||
//! Constructor
|
||||
/*! \param os Output stream.
|
||||
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||
\param levelDepth Initial capacity of stack.
|
||||
*/
|
||||
Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
|
||||
|
||||
Writer(Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
|
||||
Writer(Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
|
||||
|
||||
//! Reset the writer with a new stream.
|
||||
/*!
|
||||
This function reset the writer with a new stream and default settings,
|
||||
in order to make a Writer object reusable for output multiple JSONs.
|
||||
//! Reset the writer with a new stream.
|
||||
/*!
|
||||
This function reset the writer with a new stream and default settings,
|
||||
in order to make a Writer object reusable for output multiple JSONs.
|
||||
|
||||
\param os New output stream.
|
||||
\code
|
||||
Writer<OutputStream> writer(os1);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
\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();
|
||||
}
|
||||
writer.Reset(os2);
|
||||
writer.StartObject();
|
||||
// ...
|
||||
writer.EndObject();
|
||||
\endcode
|
||||
*/
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
hasRoot_ = false;
|
||||
level_stack_.Clear();
|
||||
}
|
||||
|
||||
//! Checks whether the output is a complete JSON.
|
||||
/*!
|
||||
A complete JSON has a complete root object or array.
|
||||
*/
|
||||
bool IsComplete() const {
|
||||
return hasRoot_ && level_stack_.Empty();
|
||||
}
|
||||
//! Checks whether the output is a complete JSON.
|
||||
/*!
|
||||
A complete JSON has a complete root object or array.
|
||||
*/
|
||||
bool IsComplete() const {
|
||||
return hasRoot_ && level_stack_.Empty();
|
||||
}
|
||||
|
||||
/*!@name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
/*!@name Implementation of Handler
|
||||
\see Handler
|
||||
*/
|
||||
//@{
|
||||
|
||||
bool Null() { Prefix(kNullType); return WriteNull(); }
|
||||
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
|
||||
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
|
||||
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
|
||||
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
|
||||
bool Null() { Prefix(kNullType); return WriteNull(); }
|
||||
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
|
||||
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
|
||||
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
|
||||
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
|
||||
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
|
||||
|
||||
//! Writes the given \c double value to the stream
|
||||
/*!
|
||||
\param d The value to be written.
|
||||
\return Whether it is succeed.
|
||||
*/
|
||||
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
|
||||
//! Writes the given \c double value to the stream
|
||||
/*!
|
||||
\param d The value to be written.
|
||||
\return Whether it is succeed.
|
||||
*/
|
||||
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
|
||||
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
Prefix(kStringType);
|
||||
return WriteString(str, length);
|
||||
}
|
||||
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||
(void)copy;
|
||||
Prefix(kStringType);
|
||||
return WriteString(str, length);
|
||||
}
|
||||
|
||||
bool StartObject() {
|
||||
Prefix(kObjectType);
|
||||
new (level_stack_.template Push<Level>()) Level(false);
|
||||
return WriteStartObject();
|
||||
}
|
||||
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 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 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;
|
||||
}
|
||||
//@}
|
||||
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 */
|
||||
//@{
|
||||
/*! @name Convenience extensions */
|
||||
//@{
|
||||
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
//! Simpler but slower overload.
|
||||
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||
|
||||
//@}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//! Information for each nested level
|
||||
struct Level {
|
||||
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
|
||||
size_t valueCount; //!< number of values in this level
|
||||
bool inArray; //!< true if in array, otherwise in object
|
||||
};
|
||||
//! Information for each nested level
|
||||
struct Level {
|
||||
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
|
||||
size_t valueCount; //!< number of values in this level
|
||||
bool inArray; //!< true if in array, otherwise in object
|
||||
};
|
||||
|
||||
static const size_t kDefaultLevelDepth = 32;
|
||||
static const size_t kDefaultLevelDepth = 32;
|
||||
|
||||
bool WriteNull() {
|
||||
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
|
||||
}
|
||||
bool WriteNull() {
|
||||
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
|
||||
}
|
||||
|
||||
bool WriteBool(bool b) {
|
||||
if (b) {
|
||||
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
|
||||
}
|
||||
else {
|
||||
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool WriteBool(bool b) {
|
||||
if (b) {
|
||||
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
|
||||
}
|
||||
else {
|
||||
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
char buffer[11];
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
bool WriteInt(int i) {
|
||||
char buffer[11];
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
char buffer[21];
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
bool WriteInt64(int64_t i64) {
|
||||
char buffer[21];
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
for (const char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char* end = internal::u64toa(u64, buffer);
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char* end = internal::u64toa(u64, buffer);
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteDouble(double d) {
|
||||
char buffer[25];
|
||||
char* end = internal::dtoa(d, buffer);
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
bool WriteDouble(double d) {
|
||||
char buffer[25];
|
||||
char* end = internal::dtoa(d, buffer);
|
||||
for (char* p = buffer; p != end; ++p)
|
||||
os_->Put(*p);
|
||||
return true;
|
||||
}
|
||||
#undef RAPIDJSON_SNPRINTF
|
||||
|
||||
bool WriteString(const Ch* str, SizeType length) {
|
||||
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const char escape[256] = {
|
||||
bool WriteString(const Ch* str, SizeType length) {
|
||||
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
static const char escape[256] = {
|
||||
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||
Z16, Z16, // 30~4F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||
#undef Z16
|
||||
};
|
||||
};
|
||||
|
||||
os_->Put('\"');
|
||||
GenericStringStream<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;
|
||||
}
|
||||
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; }
|
||||
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;
|
||||
}
|
||||
}
|
||||
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_;
|
||||
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
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
|
@ -1,12 +1,32 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#ifndef PERFTEST_H_
|
||||
#define PERFTEST_H_
|
||||
|
||||
#define TEST_RAPIDJSON 1
|
||||
#define TEST_JSONCPP 0
|
||||
#define TEST_YAJL 0
|
||||
#define TEST_RAPIDJSON 1
|
||||
#define TEST_JSONCPP 0
|
||||
#define TEST_YAJL 0
|
||||
#define TEST_ULTRAJSON 0
|
||||
#define TEST_PLATFORM 0
|
||||
#define TEST_MISC 0
|
||||
#define TEST_MISC 0
|
||||
|
||||
#define TEST_VERSION_CODE(x,y,z) \
|
||||
(((x)*100000) + ((y)*100) + (z))
|
||||
@ -55,57 +75,57 @@
|
||||
//! Base class for all performance tests
|
||||
class PerfTest : public ::testing::Test {
|
||||
public:
|
||||
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
|
||||
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
FILE *fp = fopen(filename_ = "data/sample.json", "rb");
|
||||
if (!fp)
|
||||
fp = fopen(filename_ = "../../bin/data/sample.json", "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
virtual void SetUp() {
|
||||
FILE *fp = fopen(filename_ = "data/sample.json", "rb");
|
||||
if (!fp)
|
||||
fp = fopen(filename_ = "../../bin/data/sample.json", "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
ASSERT_EQ(length_, fread(json_, 1, length_, fp));
|
||||
json_[length_] = '\0';
|
||||
fclose(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
ASSERT_EQ(length_, fread(json_, 1, length_, fp));
|
||||
json_[length_] = '\0';
|
||||
fclose(fp);
|
||||
|
||||
// whitespace test
|
||||
whitespace_length_ = 1024 * 1024;
|
||||
whitespace_ = (char *)malloc(whitespace_length_ + 4);
|
||||
char *p = whitespace_;
|
||||
for (size_t i = 0; i < whitespace_length_; i += 4) {
|
||||
*p++ = ' ';
|
||||
*p++ = '\n';
|
||||
*p++ = '\r';
|
||||
*p++ = '\t';
|
||||
}
|
||||
*p++ = '[';
|
||||
*p++ = '0';
|
||||
*p++ = ']';
|
||||
*p++ = '\0';
|
||||
}
|
||||
// whitespace test
|
||||
whitespace_length_ = 1024 * 1024;
|
||||
whitespace_ = (char *)malloc(whitespace_length_ + 4);
|
||||
char *p = whitespace_;
|
||||
for (size_t i = 0; i < whitespace_length_; i += 4) {
|
||||
*p++ = ' ';
|
||||
*p++ = '\n';
|
||||
*p++ = '\r';
|
||||
*p++ = '\t';
|
||||
}
|
||||
*p++ = '[';
|
||||
*p++ = '0';
|
||||
*p++ = ']';
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
free(whitespace_);
|
||||
json_ = 0;
|
||||
whitespace_ = 0;
|
||||
}
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
free(whitespace_);
|
||||
json_ = 0;
|
||||
whitespace_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
PerfTest(const PerfTest&);
|
||||
PerfTest& operator=(const PerfTest&);
|
||||
PerfTest(const PerfTest&);
|
||||
PerfTest& operator=(const PerfTest&);
|
||||
|
||||
protected:
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
char *whitespace_;
|
||||
size_t whitespace_length_;
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
char *whitespace_;
|
||||
size_t whitespace_length_;
|
||||
|
||||
static const size_t kTrialCount = 1000;
|
||||
static const size_t kTrialCount = 1000;
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
||||
|
@ -1,3 +1,23 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
// This file is for giving the performance characteristics of the platform (compiler/OS/CPU).
|
||||
@ -22,130 +42,130 @@
|
||||
|
||||
class Platform : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
|
||||
// temp buffer for testing
|
||||
temp_ = (char *)malloc(length_ + 1);
|
||||
memcpy(temp_, json_, length_);
|
||||
checkSum_ = CheckSum();
|
||||
}
|
||||
// temp buffer for testing
|
||||
temp_ = (char *)malloc(length_ + 1);
|
||||
memcpy(temp_, json_, length_);
|
||||
checkSum_ = CheckSum();
|
||||
}
|
||||
|
||||
char CheckSum() {
|
||||
char c = 0;
|
||||
for (size_t i = 0; i < length_; ++i)
|
||||
c += temp_[i];
|
||||
return c;
|
||||
}
|
||||
char CheckSum() {
|
||||
char c = 0;
|
||||
for (size_t i = 0; i < length_; ++i)
|
||||
c += temp_[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
free(temp_);
|
||||
}
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
free(temp_);
|
||||
}
|
||||
|
||||
protected:
|
||||
char *temp_;
|
||||
char checkSum_;
|
||||
char *temp_;
|
||||
char checkSum_;
|
||||
};
|
||||
|
||||
TEST_F(Platform, CheckSum) {
|
||||
for (int i = 0; i < kTrialCount; i++)
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
for (int i = 0; i < kTrialCount; i++)
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
}
|
||||
|
||||
TEST_F(Platform, strlen) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strlen(json_);
|
||||
EXPECT_EQ(length_, l);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strlen(json_);
|
||||
EXPECT_EQ(length_, l);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Platform, memcmp) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
EXPECT_EQ(0, memcmp(temp_, json_, length_));
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
EXPECT_EQ(0, memcmp(temp_, json_, length_));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Platform, pow) {
|
||||
double sum = 0;
|
||||
for (int i = 0; i < kTrialCount * kTrialCount; i++)
|
||||
sum += pow(10.0, i & 255);
|
||||
EXPECT_GT(sum, 0.0);
|
||||
double sum = 0;
|
||||
for (int i = 0; i < kTrialCount * kTrialCount; i++)
|
||||
sum += pow(10.0, i & 255);
|
||||
EXPECT_GT(sum, 0.0);
|
||||
}
|
||||
|
||||
TEST_F(Platform, Whitespace_strlen) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strlen(whitespace_);
|
||||
EXPECT_GT(l, whitespace_length_);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strlen(whitespace_);
|
||||
EXPECT_GT(l, whitespace_length_);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Platform, Whitespace_strspn) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strspn(whitespace_, " \n\r\t");
|
||||
EXPECT_EQ(whitespace_length_, l);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
size_t l = strspn(whitespace_, " \n\r\t");
|
||||
EXPECT_EQ(whitespace_length_, l);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Platform, fread) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
ASSERT_EQ(length_, fread(temp_, 1, length_, fp));
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
fclose(fp);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
ASSERT_EQ(length_, fread(temp_, 1, length_, fp));
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
TEST_F(Platform, read) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
int fd = _open(filename_, _O_BINARY | _O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
ASSERT_EQ(length_, _read(fd, temp_, length_));
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
_close(fd);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
int fd = _open(filename_, _O_BINARY | _O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
ASSERT_EQ(length_, _read(fd, temp_, length_));
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
_close(fd);
|
||||
}
|
||||
}
|
||||
#else
|
||||
TEST_F(Platform, read) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
int fd = open(filename_, O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
ASSERT_EQ(length_, read(fd, temp_, length_));
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
close(fd);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
int fd = open(filename_, O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
ASSERT_EQ(length_, read(fd, temp_, length_));
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST_F(Platform, MapViewOfFile) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
HANDLE file = CreateFile(filename_, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, file);
|
||||
HANDLE mapObject = CreateFileMapping(file, NULL, PAGE_READONLY, 0, length_, NULL);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, mapObject);
|
||||
void *p = MapViewOfFile(mapObject, FILE_MAP_READ, 0, 0, length_);
|
||||
ASSERT_TRUE(p != NULL);
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
ASSERT_TRUE(UnmapViewOfFile(p) == TRUE);
|
||||
ASSERT_TRUE(CloseHandle(mapObject) == TRUE);
|
||||
ASSERT_TRUE(CloseHandle(file) == TRUE);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
HANDLE file = CreateFile(filename_, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, file);
|
||||
HANDLE mapObject = CreateFileMapping(file, NULL, PAGE_READONLY, 0, length_, NULL);
|
||||
ASSERT_NE(INVALID_HANDLE_VALUE, mapObject);
|
||||
void *p = MapViewOfFile(mapObject, FILE_MAP_READ, 0, 0, length_);
|
||||
ASSERT_TRUE(p != NULL);
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
ASSERT_TRUE(UnmapViewOfFile(p) == TRUE);
|
||||
ASSERT_TRUE(CloseHandle(mapObject) == TRUE);
|
||||
ASSERT_TRUE(CloseHandle(file) == TRUE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_MAPPED_FILES
|
||||
TEST_F(Platform, mmap) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
int fd = open(filename_, O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
void *p = mmap(NULL, length_, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
ASSERT_TRUE(p != NULL);
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
munmap(p, length_);
|
||||
close(fd);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
int fd = open(filename_, O_RDONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
void *p = mmap(NULL, length_, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
ASSERT_TRUE(p != NULL);
|
||||
EXPECT_EQ(checkSum_, CheckSum());
|
||||
munmap(p, length_);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -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;
|
||||
size_t count = 1;
|
||||
switch(value.GetType()) {
|
||||
case kObjectType:
|
||||
for (typename T::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
|
||||
count++; // name
|
||||
count += Traverse(itr->value);
|
||||
}
|
||||
break;
|
||||
|
||||
case kArrayType:
|
||||
for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr)
|
||||
count += Traverse(*itr);
|
||||
break;
|
||||
case kArrayType:
|
||||
for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr)
|
||||
count += Traverse(*itr);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, DocumentTraverse) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
size_t count = Traverse(doc_);
|
||||
EXPECT_EQ(4339u, count);
|
||||
//if (i == 0)
|
||||
// std::cout << count << std::endl;
|
||||
}
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
size_t count = Traverse(doc_);
|
||||
EXPECT_EQ(4339u, count);
|
||||
//if (i == 0)
|
||||
// std::cout << count << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
@ -185,12 +205,12 @@ RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
struct ValueCounter : public BaseReaderHandler<> {
|
||||
ValueCounter() : count_(1) {} // root
|
||||
ValueCounter() : count_(1) {} // root
|
||||
|
||||
bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; }
|
||||
bool EndArray(SizeType elementCount) { count_ += elementCount; return true; }
|
||||
bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; }
|
||||
bool EndArray(SizeType elementCount) { count_ += elementCount; return true; }
|
||||
|
||||
SizeType count_;
|
||||
SizeType count_;
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
@ -198,113 +218,113 @@ RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
TEST_F(RapidJson, DocumentAccept) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
ValueCounter counter;
|
||||
doc_.Accept(counter);
|
||||
EXPECT_EQ(4339u, counter.count_);
|
||||
}
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
ValueCounter counter;
|
||||
doc_.Accept(counter);
|
||||
EXPECT_EQ(4339u, counter.count_);
|
||||
}
|
||||
}
|
||||
|
||||
struct NullStream {
|
||||
NullStream() /*: length_(0)*/ {}
|
||||
void Put(char) { /*++length_;*/ }
|
||||
void Flush() {}
|
||||
//size_t length_;
|
||||
NullStream() /*: length_(0)*/ {}
|
||||
void Put(char) { /*++length_;*/ }
|
||||
void Flush() {}
|
||||
//size_t length_;
|
||||
};
|
||||
|
||||
TEST_F(RapidJson, Writer_NullStream) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
NullStream s;
|
||||
Writer<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;
|
||||
NullStream os;
|
||||
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
StringStream is(json_);
|
||||
bool result = true;
|
||||
while (is.Peek() != '\0')
|
||||
result &= UTF8<>::Validate(is, os);
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
StringStream is(json_);
|
||||
bool result = true;
|
||||
while (is.Peek() != '\0')
|
||||
result &= UTF8<>::Validate(is, os);
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Depreciated.
|
||||
//TEST_F(RapidJson, FileStream_Read) {
|
||||
// for (size_t i = 0; i < kTrialCount; i++) {
|
||||
// FILE *fp = fopen(filename_, "rb");
|
||||
// FileStream s(fp);
|
||||
// while (s.Take() != '\0')
|
||||
// ;
|
||||
// fclose(fp);
|
||||
// }
|
||||
// for (size_t i = 0; i < kTrialCount; i++) {
|
||||
// FILE *fp = fopen(filename_, "rb");
|
||||
// FileStream s(fp);
|
||||
// while (s.Take() != '\0')
|
||||
// ;
|
||||
// fclose(fp);
|
||||
// }
|
||||
//}
|
||||
|
||||
TEST_F(RapidJson, FileReadStream) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
char buffer[65536];
|
||||
FileReadStream s(fp, buffer, sizeof(buffer));
|
||||
while (s.Take() != '\0')
|
||||
;
|
||||
fclose(fp);
|
||||
}
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
char buffer[65536];
|
||||
FileReadStream s(fp, buffer, sizeof(buffer));
|
||||
while (s.Take() != '\0')
|
||||
;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
char buffer[65536];
|
||||
FileReadStream s(fp, buffer, sizeof(buffer));
|
||||
BaseReaderHandler<> h;
|
||||
Reader reader;
|
||||
reader.Parse(s, h);
|
||||
fclose(fp);
|
||||
}
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
char buffer[65536];
|
||||
FileReadStream s(fp, buffer, sizeof(buffer));
|
||||
BaseReaderHandler<> h;
|
||||
Reader reader;
|
||||
reader.Parse(s, h);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_RAPIDJSON
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,23 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_YAJL
|
||||
@ -10,19 +30,19 @@ extern "C" {
|
||||
|
||||
class Yajl : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
root_ = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root_ != NULL);
|
||||
}
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
root_ = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root_ != NULL);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
yajl_tree_free(root_);
|
||||
}
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
yajl_tree_free(root_);
|
||||
}
|
||||
|
||||
protected:
|
||||
yajl_val root_;
|
||||
yajl_val root_;
|
||||
};
|
||||
|
||||
static int null_null(void *) { return 1; }
|
||||
@ -37,152 +57,152 @@ static int null_start_array(void*) { return 1; }
|
||||
static int null_end_array(void *) { return 1; }
|
||||
|
||||
static yajl_callbacks nullcallbacks = {
|
||||
null_null,
|
||||
null_boolean,
|
||||
null_integer,
|
||||
null_double,
|
||||
NULL, // yajl_number(). Here we want to test full-parsing performance.
|
||||
null_string,
|
||||
null_start_map,
|
||||
null_map_key,
|
||||
null_end_map,
|
||||
null_start_array,
|
||||
null_end_array
|
||||
null_null,
|
||||
null_boolean,
|
||||
null_integer,
|
||||
null_double,
|
||||
NULL, // yajl_number(). Here we want to test full-parsing performance.
|
||||
null_string,
|
||||
null_start_map,
|
||||
null_map_key,
|
||||
null_end_map,
|
||||
null_start_array,
|
||||
null_end_array
|
||||
};
|
||||
|
||||
TEST_F(Yajl, yajl_parse_nullcallbacks) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_handle hand = yajl_alloc(&nullcallbacks, NULL, NULL);
|
||||
yajl_status stat = yajl_parse(hand, (unsigned char*)json_, length_);
|
||||
//ASSERT_EQ(yajl_status_ok, stat);
|
||||
if (stat != yajl_status_ok) {
|
||||
unsigned char * str = yajl_get_error(hand, 1, (unsigned char*)json_, length_);
|
||||
fprintf(stderr, "%s", (const char *) str);
|
||||
}
|
||||
stat = yajl_complete_parse(hand);
|
||||
ASSERT_EQ(yajl_status_ok, stat);
|
||||
yajl_free(hand);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_handle hand = yajl_alloc(&nullcallbacks, NULL, NULL);
|
||||
yajl_status stat = yajl_parse(hand, (unsigned char*)json_, length_);
|
||||
//ASSERT_EQ(yajl_status_ok, stat);
|
||||
if (stat != yajl_status_ok) {
|
||||
unsigned char * str = yajl_get_error(hand, 1, (unsigned char*)json_, length_);
|
||||
fprintf(stderr, "%s", (const char *) str);
|
||||
}
|
||||
stat = yajl_complete_parse(hand);
|
||||
ASSERT_EQ(yajl_status_ok, stat);
|
||||
yajl_free(hand);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_tree_parse) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(json_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
}
|
||||
|
||||
yajl_gen_status GenVal(yajl_gen g, yajl_val v) {
|
||||
yajl_gen_status status;
|
||||
switch (v->type) {
|
||||
case yajl_t_string: return yajl_gen_string(g, (unsigned char*)v->u.string, strlen(v->u.string));
|
||||
yajl_gen_status status;
|
||||
switch (v->type) {
|
||||
case yajl_t_string: return yajl_gen_string(g, (unsigned char*)v->u.string, strlen(v->u.string));
|
||||
|
||||
case yajl_t_number:
|
||||
{
|
||||
char buffer[100];
|
||||
char *num = buffer;
|
||||
size_t len;
|
||||
//if (YAJL_IS_INTEGER(v)) // buggy
|
||||
if (v->u.number.flags & YAJL_NUMBER_INT_VALID)
|
||||
case yajl_t_number:
|
||||
{
|
||||
char buffer[100];
|
||||
char *num = buffer;
|
||||
size_t len;
|
||||
//if (YAJL_IS_INTEGER(v)) // buggy
|
||||
if (v->u.number.flags & YAJL_NUMBER_INT_VALID)
|
||||
#if _MSC_VER
|
||||
len = sprintf(num, "%I64d", YAJL_GET_INTEGER(v));
|
||||
len = sprintf(num, "%I64d", YAJL_GET_INTEGER(v));
|
||||
#else
|
||||
len = sprintf(num, "%lld", YAJL_GET_INTEGER(v));
|
||||
len = sprintf(num, "%lld", YAJL_GET_INTEGER(v));
|
||||
#endif
|
||||
//else if (YAJL_IS_DOUBLE(v)) // buggy
|
||||
else if (v->u.number.flags & YAJL_NUMBER_DOUBLE_VALID)
|
||||
len = sprintf(num, "%g", YAJL_GET_DOUBLE(v));
|
||||
else {
|
||||
num = YAJL_GET_NUMBER(v);
|
||||
len = strlen(buffer);
|
||||
}
|
||||
return yajl_gen_number(g, num, len);
|
||||
}
|
||||
//else if (YAJL_IS_DOUBLE(v)) // buggy
|
||||
else if (v->u.number.flags & YAJL_NUMBER_DOUBLE_VALID)
|
||||
len = sprintf(num, "%g", YAJL_GET_DOUBLE(v));
|
||||
else {
|
||||
num = YAJL_GET_NUMBER(v);
|
||||
len = strlen(buffer);
|
||||
}
|
||||
return yajl_gen_number(g, num, len);
|
||||
}
|
||||
|
||||
case yajl_t_object:
|
||||
status = yajl_gen_map_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.object.len; i++) {
|
||||
status = yajl_gen_string(g, (unsigned char *)v->u.object.keys[i], strlen(v->u.object.keys[i]));
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
status = GenVal(g, v->u.object.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
return yajl_gen_map_close(g);
|
||||
case yajl_t_object:
|
||||
status = yajl_gen_map_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.object.len; i++) {
|
||||
status = yajl_gen_string(g, (unsigned char *)v->u.object.keys[i], strlen(v->u.object.keys[i]));
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
status = GenVal(g, v->u.object.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
return yajl_gen_map_close(g);
|
||||
|
||||
case yajl_t_array:
|
||||
status = yajl_gen_array_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.array.len; i++) {
|
||||
status = GenVal(g, v->u.array.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
case yajl_t_array:
|
||||
status = yajl_gen_array_open(g);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
|
||||
for (size_t i = 0; i < v->u.array.len; i++) {
|
||||
status = GenVal(g, v->u.array.values[i]);
|
||||
if (status != yajl_gen_status_ok)
|
||||
return status;
|
||||
}
|
||||
|
||||
return yajl_gen_array_close(g);
|
||||
return yajl_gen_array_close(g);
|
||||
|
||||
case yajl_t_true: return yajl_gen_bool(g, 1);
|
||||
case yajl_t_false: return yajl_gen_bool(g, 0);
|
||||
case yajl_t_null: return yajl_gen_null(g);
|
||||
}
|
||||
return yajl_gen_in_error_state;
|
||||
case yajl_t_true: return yajl_gen_bool(g, 1);
|
||||
case yajl_t_false: return yajl_gen_bool(g, 0);
|
||||
case yajl_t_null: return yajl_gen_null(g);
|
||||
}
|
||||
return yajl_gen_in_error_state;
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_gen) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, yajl_gen_beautify) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
yajl_gen_config(g, yajl_gen_beautify, 1);
|
||||
yajl_gen_config(g, yajl_gen_indent_string, " ");
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_gen g = yajl_gen_alloc(NULL);
|
||||
yajl_gen_config(g, yajl_gen_beautify, 1);
|
||||
yajl_gen_config(g, yajl_gen_indent_string, " ");
|
||||
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
yajl_gen_status status = GenVal(g, root_);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
std::cout << "gen error: " << status << std::endl;
|
||||
FAIL();
|
||||
}
|
||||
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
const unsigned char * buf;
|
||||
size_t len;
|
||||
status = yajl_gen_get_buf(g, &buf, &len);
|
||||
ASSERT_EQ(yajl_gen_status_ok, status);
|
||||
//if (i == 0)
|
||||
// std::cout << len << std::endl;
|
||||
yajl_gen_free(g);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Yajl, Whitespace) {
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(whitespace_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
for (int i = 0; i < kTrialCount; i++) {
|
||||
yajl_val root = yajl_tree_parse(whitespace_, NULL, 0);
|
||||
ASSERT_TRUE(root != NULL);
|
||||
yajl_tree_free(root);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TEST_YAJL
|
||||
|
@ -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);
|
||||
// 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());
|
||||
GenericDocument<UTF16<> > d;
|
||||
d.ParseStream<0, UTF8<> >(eis);
|
||||
EXPECT_FALSE(d.HasParseError());
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
|
||||
wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
|
||||
GenericValue<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()));
|
||||
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);
|
||||
// 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);
|
||||
{
|
||||
// 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()));
|
||||
}
|
||||
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);
|
||||
// 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());
|
||||
Document d;
|
||||
d.ParseStream<0, AutoUTF<unsigned> >(eis);
|
||||
EXPECT_FALSE(d.HasParseError());
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
|
||||
char expected[] = "I can eat glass and it doesn't hurt me.";
|
||||
Value& v = d["en"];
|
||||
EXPECT_TRUE(v.IsString());
|
||||
EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength());
|
||||
EXPECT_EQ(0, StrCmp(expected, v.GetString()));
|
||||
char expected[] = "I can eat glass and it doesn't hurt me.";
|
||||
Value& v = d["en"];
|
||||
EXPECT_TRUE(v.IsString());
|
||||
EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength());
|
||||
EXPECT_EQ(0, StrCmp(expected, v.GetString()));
|
||||
|
||||
// UTF8 -> UTF8 in memory
|
||||
StringBuffer bos;
|
||||
Writer<StringBuffer> writer(bos);
|
||||
d.Accept(writer);
|
||||
// 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);
|
||||
{
|
||||
// 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()));
|
||||
}
|
||||
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;
|
||||
//}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,23 @@
|
||||
// Copyright (C) 2011 Milo Yip
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/filestream.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
@ -8,96 +28,96 @@ using namespace rapidjson;
|
||||
|
||||
class FileStreamTest : public ::testing::Test {
|
||||
public:
|
||||
FileStreamTest() : filename_(), json_(), length_() {}
|
||||
FileStreamTest() : filename_(), json_(), length_() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
FILE *fp = fopen(filename_ = "data/sample.json", "rb");
|
||||
if (!fp)
|
||||
fp = fopen(filename_ = "../../bin/data/sample.json", "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
virtual void SetUp() {
|
||||
FILE *fp = fopen(filename_ = "data/sample.json", "rb");
|
||||
if (!fp)
|
||||
fp = fopen(filename_ = "../../bin/data/sample.json", "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
size_t readLength = fread(json_, 1, length_, fp);
|
||||
json_[readLength] = '\0';
|
||||
fclose(fp);
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
size_t readLength = fread(json_, 1, length_, fp);
|
||||
json_[readLength] = '\0';
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
json_ = 0;
|
||||
}
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
json_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
FileStreamTest(const FileStreamTest&);
|
||||
FileStreamTest& operator=(const FileStreamTest&);
|
||||
|
||||
FileStreamTest(const FileStreamTest&);
|
||||
FileStreamTest& operator=(const FileStreamTest&);
|
||||
|
||||
protected:
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
// Depreciated
|
||||
//TEST_F(FileStreamTest, FileStream_Read) {
|
||||
// FILE *fp = fopen(filename_, "rb");
|
||||
// ASSERT_TRUE(fp != 0);
|
||||
// FileStream s(fp);
|
||||
// FILE *fp = fopen(filename_, "rb");
|
||||
// ASSERT_TRUE(fp != 0);
|
||||
// FileStream s(fp);
|
||||
//
|
||||
// for (size_t i = 0; i < length_; i++) {
|
||||
// EXPECT_EQ(json_[i], s.Peek());
|
||||
// EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same
|
||||
// EXPECT_EQ(json_[i], s.Take());
|
||||
// }
|
||||
// for (size_t i = 0; i < length_; i++) {
|
||||
// EXPECT_EQ(json_[i], s.Peek());
|
||||
// EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same
|
||||
// EXPECT_EQ(json_[i], s.Take());
|
||||
// }
|
||||
//
|
||||
// EXPECT_EQ(length_, s.Tell());
|
||||
// EXPECT_EQ('\0', s.Peek());
|
||||
// EXPECT_EQ(length_, s.Tell());
|
||||
// EXPECT_EQ('\0', s.Peek());
|
||||
//
|
||||
// fclose(fp);
|
||||
// fclose(fp);
|
||||
//}
|
||||
|
||||
TEST_F(FileStreamTest, FileReadStream) {
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
char buffer[65536];
|
||||
FileReadStream s(fp, buffer, sizeof(buffer));
|
||||
FILE *fp = fopen(filename_, "rb");
|
||||
ASSERT_TRUE(fp != 0);
|
||||
char buffer[65536];
|
||||
FileReadStream s(fp, buffer, sizeof(buffer));
|
||||
|
||||
for (size_t i = 0; i < length_; i++) {
|
||||
EXPECT_EQ(json_[i], s.Peek());
|
||||
EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same
|
||||
EXPECT_EQ(json_[i], s.Take());
|
||||
}
|
||||
for (size_t i = 0; i < length_; i++) {
|
||||
EXPECT_EQ(json_[i], s.Peek());
|
||||
EXPECT_EQ(json_[i], s.Peek()); // 2nd time should be the same
|
||||
EXPECT_EQ(json_[i], s.Take());
|
||||
}
|
||||
|
||||
EXPECT_EQ(length_, s.Tell());
|
||||
EXPECT_EQ('\0', s.Peek());
|
||||
EXPECT_EQ(length_, s.Tell());
|
||||
EXPECT_EQ('\0', s.Peek());
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
TEST_F(FileStreamTest, FileWriteStream) {
|
||||
char filename[L_tmpnam];
|
||||
TempFilename(filename);
|
||||
char filename[L_tmpnam];
|
||||
TempFilename(filename);
|
||||
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
char buffer[65536];
|
||||
FileWriteStream os(fp, buffer, sizeof(buffer));
|
||||
for (size_t i = 0; i < length_; i++)
|
||||
os.Put(json_[i]);
|
||||
os.Flush();
|
||||
fclose(fp);
|
||||
FILE *fp = fopen(filename, "wb");
|
||||
char buffer[65536];
|
||||
FileWriteStream os(fp, buffer, sizeof(buffer));
|
||||
for (size_t i = 0; i < length_; i++)
|
||||
os.Put(json_[i]);
|
||||
os.Flush();
|
||||
fclose(fp);
|
||||
|
||||
// Read it back to verify
|
||||
fp = fopen(filename, "rb");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
// Read it back to verify
|
||||
fp = fopen(filename, "rb");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
|
||||
for (size_t i = 0; i < length_; i++)
|
||||
EXPECT_EQ(json_[i], is.Take());
|
||||
for (size_t i = 0; i < length_; i++)
|
||||
EXPECT_EQ(json_[i], is.Take());
|
||||
|
||||
EXPECT_EQ(length_, is.Tell());
|
||||
fclose(fp);
|
||||
EXPECT_EQ(length_, is.Tell());
|
||||
fclose(fp);
|
||||
|
||||
//std::cout << filename << std::endl;
|
||||
remove(filename);
|
||||
//std::cout << filename << std::endl;
|
||||
remove(filename);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
|
@ -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))
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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\"}";
|
||||
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 -> 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);
|
||||
// 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);
|
||||
StringBuffer buffer2;
|
||||
Writer<StringBuffer> writer2(buffer2);
|
||||
GenericReader<ASCII<>, UTF8<> > reader2;
|
||||
StringStream s2(buffer.GetString());
|
||||
reader2.Parse(s2, writer2);
|
||||
|
||||
EXPECT_STREQ(json, buffer2.GetString());
|
||||
}
|
||||
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);
|
||||
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());
|
||||
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());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user