mirror of
https://github.com/Tencent/rapidjson.git
synced 2025-03-06 04:55:50 +01:00
Revert "Normalize all the line endings"
This reverts commit 6047e3ce128954ec594e9a893ef2125c9f9b61c7.
This commit is contained in:
parent
6047e3ce12
commit
7fb84d304b
@ -1,22 +1,22 @@
|
||||
{
|
||||
"glossary": {
|
||||
"title": "example glossary",
|
||||
"GlossDiv": {
|
||||
"title": "S",
|
||||
"GlossList": {
|
||||
"GlossEntry": {
|
||||
"ID": "SGML",
|
||||
"SortAs": "SGML",
|
||||
"GlossTerm": "Standard Generalized Markup Language",
|
||||
"Acronym": "SGML",
|
||||
"Abbrev": "ISO 8879:1986",
|
||||
"GlossDef": {
|
||||
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||
"GlossSeeAlso": ["GML", "XML"]
|
||||
},
|
||||
"GlossSee": "markup"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"glossary": {
|
||||
"title": "example glossary",
|
||||
"GlossDiv": {
|
||||
"title": "S",
|
||||
"GlossList": {
|
||||
"GlossEntry": {
|
||||
"ID": "SGML",
|
||||
"SortAs": "SGML",
|
||||
"GlossTerm": "Standard Generalized Markup Language",
|
||||
"Acronym": "SGML",
|
||||
"Abbrev": "ISO 8879:1986",
|
||||
"GlossDef": {
|
||||
"para": "A meta-markup language, used to create markup languages such as DocBook.",
|
||||
"GlossSeeAlso": ["GML", "XML"]
|
||||
},
|
||||
"GlossSee": "markup"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +1,27 @@
|
||||
{"menu": {
|
||||
"header": "SVG Viewer",
|
||||
"items": [
|
||||
{"id": "Open"},
|
||||
{"id": "OpenNew", "label": "Open New"},
|
||||
null,
|
||||
{"id": "ZoomIn", "label": "Zoom In"},
|
||||
{"id": "ZoomOut", "label": "Zoom Out"},
|
||||
{"id": "OriginalView", "label": "Original View"},
|
||||
null,
|
||||
{"id": "Quality"},
|
||||
{"id": "Pause"},
|
||||
{"id": "Mute"},
|
||||
null,
|
||||
{"id": "Find", "label": "Find..."},
|
||||
{"id": "FindAgain", "label": "Find Again"},
|
||||
{"id": "Copy"},
|
||||
{"id": "CopyAgain", "label": "Copy Again"},
|
||||
{"id": "CopySVG", "label": "Copy SVG"},
|
||||
{"id": "ViewSVG", "label": "View SVG"},
|
||||
{"id": "ViewSource", "label": "View Source"},
|
||||
{"id": "SaveAs", "label": "Save As"},
|
||||
null,
|
||||
{"id": "Help"},
|
||||
{"id": "About", "label": "About Adobe CVG Viewer..."}
|
||||
]
|
||||
{"menu": {
|
||||
"header": "SVG Viewer",
|
||||
"items": [
|
||||
{"id": "Open"},
|
||||
{"id": "OpenNew", "label": "Open New"},
|
||||
null,
|
||||
{"id": "ZoomIn", "label": "Zoom In"},
|
||||
{"id": "ZoomOut", "label": "Zoom Out"},
|
||||
{"id": "OriginalView", "label": "Original View"},
|
||||
null,
|
||||
{"id": "Quality"},
|
||||
{"id": "Pause"},
|
||||
{"id": "Mute"},
|
||||
null,
|
||||
{"id": "Find", "label": "Find..."},
|
||||
{"id": "FindAgain", "label": "Find Again"},
|
||||
{"id": "Copy"},
|
||||
{"id": "CopyAgain", "label": "Copy Again"},
|
||||
{"id": "CopySVG", "label": "Copy SVG"},
|
||||
{"id": "ViewSVG", "label": "View SVG"},
|
||||
{"id": "ViewSource", "label": "View Source"},
|
||||
{"id": "SaveAs", "label": "Save As"},
|
||||
null,
|
||||
{"id": "Help"},
|
||||
{"id": "About", "label": "About Adobe CVG Viewer..."}
|
||||
]
|
||||
}}
|
@ -1 +1 @@
|
||||
sample.json is obtained from http://code.google.com/p/json-test-suite/downloads/detail?name=sample.zip
|
||||
sample.json is obtained from http://code.google.com/p/json-test-suite/downloads/detail?name=sample.zip
|
||||
|
@ -1,88 +1,88 @@
|
||||
{"web-app": {
|
||||
"servlet": [
|
||||
{
|
||||
"servlet-name": "cofaxCDS",
|
||||
"servlet-class": "org.cofax.cds.CDSServlet",
|
||||
"init-param": {
|
||||
"configGlossary:installationAt": "Philadelphia, PA",
|
||||
"configGlossary:adminEmail": "ksm@pobox.com",
|
||||
"configGlossary:poweredBy": "Cofax",
|
||||
"configGlossary:poweredByIcon": "/images/cofax.gif",
|
||||
"configGlossary:staticPath": "/content/static",
|
||||
"templateProcessorClass": "org.cofax.WysiwygTemplate",
|
||||
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
|
||||
"templatePath": "templates",
|
||||
"templateOverridePath": "",
|
||||
"defaultListTemplate": "listTemplate.htm",
|
||||
"defaultFileTemplate": "articleTemplate.htm",
|
||||
"useJSP": false,
|
||||
"jspListTemplate": "listTemplate.jsp",
|
||||
"jspFileTemplate": "articleTemplate.jsp",
|
||||
"cachePackageTagsTrack": 200,
|
||||
"cachePackageTagsStore": 200,
|
||||
"cachePackageTagsRefresh": 60,
|
||||
"cacheTemplatesTrack": 100,
|
||||
"cacheTemplatesStore": 50,
|
||||
"cacheTemplatesRefresh": 15,
|
||||
"cachePagesTrack": 200,
|
||||
"cachePagesStore": 100,
|
||||
"cachePagesRefresh": 10,
|
||||
"cachePagesDirtyRead": 10,
|
||||
"searchEngineListTemplate": "forSearchEnginesList.htm",
|
||||
"searchEngineFileTemplate": "forSearchEngines.htm",
|
||||
"searchEngineRobotsDb": "WEB-INF/robots.db",
|
||||
"useDataStore": true,
|
||||
"dataStoreClass": "org.cofax.SqlDataStore",
|
||||
"redirectionClass": "org.cofax.SqlRedirection",
|
||||
"dataStoreName": "cofax",
|
||||
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
|
||||
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
|
||||
"dataStoreUser": "sa",
|
||||
"dataStorePassword": "dataStoreTestQuery",
|
||||
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
|
||||
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
|
||||
"dataStoreInitConns": 10,
|
||||
"dataStoreMaxConns": 100,
|
||||
"dataStoreConnUsageLimit": 100,
|
||||
"dataStoreLogLevel": "debug",
|
||||
"maxUrlLength": 500}},
|
||||
{
|
||||
"servlet-name": "cofaxEmail",
|
||||
"servlet-class": "org.cofax.cds.EmailServlet",
|
||||
"init-param": {
|
||||
"mailHost": "mail1",
|
||||
"mailHostOverride": "mail2"}},
|
||||
{
|
||||
"servlet-name": "cofaxAdmin",
|
||||
"servlet-class": "org.cofax.cds.AdminServlet"},
|
||||
|
||||
{
|
||||
"servlet-name": "fileServlet",
|
||||
"servlet-class": "org.cofax.cds.FileServlet"},
|
||||
{
|
||||
"servlet-name": "cofaxTools",
|
||||
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
|
||||
"init-param": {
|
||||
"templatePath": "toolstemplates/",
|
||||
"log": 1,
|
||||
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
|
||||
"logMaxSize": "",
|
||||
"dataLog": 1,
|
||||
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
|
||||
"dataLogMaxSize": "",
|
||||
"removePageCache": "/content/admin/remove?cache=pages&id=",
|
||||
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
|
||||
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
|
||||
"lookInContext": 1,
|
||||
"adminGroupID": 4,
|
||||
"betaServer": true}}],
|
||||
"servlet-mapping": {
|
||||
"cofaxCDS": "/",
|
||||
"cofaxEmail": "/cofaxutil/aemail/*",
|
||||
"cofaxAdmin": "/admin/*",
|
||||
"fileServlet": "/static/*",
|
||||
"cofaxTools": "/tools/*"},
|
||||
|
||||
"taglib": {
|
||||
"taglib-uri": "cofax.tld",
|
||||
{"web-app": {
|
||||
"servlet": [
|
||||
{
|
||||
"servlet-name": "cofaxCDS",
|
||||
"servlet-class": "org.cofax.cds.CDSServlet",
|
||||
"init-param": {
|
||||
"configGlossary:installationAt": "Philadelphia, PA",
|
||||
"configGlossary:adminEmail": "ksm@pobox.com",
|
||||
"configGlossary:poweredBy": "Cofax",
|
||||
"configGlossary:poweredByIcon": "/images/cofax.gif",
|
||||
"configGlossary:staticPath": "/content/static",
|
||||
"templateProcessorClass": "org.cofax.WysiwygTemplate",
|
||||
"templateLoaderClass": "org.cofax.FilesTemplateLoader",
|
||||
"templatePath": "templates",
|
||||
"templateOverridePath": "",
|
||||
"defaultListTemplate": "listTemplate.htm",
|
||||
"defaultFileTemplate": "articleTemplate.htm",
|
||||
"useJSP": false,
|
||||
"jspListTemplate": "listTemplate.jsp",
|
||||
"jspFileTemplate": "articleTemplate.jsp",
|
||||
"cachePackageTagsTrack": 200,
|
||||
"cachePackageTagsStore": 200,
|
||||
"cachePackageTagsRefresh": 60,
|
||||
"cacheTemplatesTrack": 100,
|
||||
"cacheTemplatesStore": 50,
|
||||
"cacheTemplatesRefresh": 15,
|
||||
"cachePagesTrack": 200,
|
||||
"cachePagesStore": 100,
|
||||
"cachePagesRefresh": 10,
|
||||
"cachePagesDirtyRead": 10,
|
||||
"searchEngineListTemplate": "forSearchEnginesList.htm",
|
||||
"searchEngineFileTemplate": "forSearchEngines.htm",
|
||||
"searchEngineRobotsDb": "WEB-INF/robots.db",
|
||||
"useDataStore": true,
|
||||
"dataStoreClass": "org.cofax.SqlDataStore",
|
||||
"redirectionClass": "org.cofax.SqlRedirection",
|
||||
"dataStoreName": "cofax",
|
||||
"dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
|
||||
"dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
|
||||
"dataStoreUser": "sa",
|
||||
"dataStorePassword": "dataStoreTestQuery",
|
||||
"dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
|
||||
"dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
|
||||
"dataStoreInitConns": 10,
|
||||
"dataStoreMaxConns": 100,
|
||||
"dataStoreConnUsageLimit": 100,
|
||||
"dataStoreLogLevel": "debug",
|
||||
"maxUrlLength": 500}},
|
||||
{
|
||||
"servlet-name": "cofaxEmail",
|
||||
"servlet-class": "org.cofax.cds.EmailServlet",
|
||||
"init-param": {
|
||||
"mailHost": "mail1",
|
||||
"mailHostOverride": "mail2"}},
|
||||
{
|
||||
"servlet-name": "cofaxAdmin",
|
||||
"servlet-class": "org.cofax.cds.AdminServlet"},
|
||||
|
||||
{
|
||||
"servlet-name": "fileServlet",
|
||||
"servlet-class": "org.cofax.cds.FileServlet"},
|
||||
{
|
||||
"servlet-name": "cofaxTools",
|
||||
"servlet-class": "org.cofax.cms.CofaxToolsServlet",
|
||||
"init-param": {
|
||||
"templatePath": "toolstemplates/",
|
||||
"log": 1,
|
||||
"logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
|
||||
"logMaxSize": "",
|
||||
"dataLog": 1,
|
||||
"dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
|
||||
"dataLogMaxSize": "",
|
||||
"removePageCache": "/content/admin/remove?cache=pages&id=",
|
||||
"removeTemplateCache": "/content/admin/remove?cache=templates&id=",
|
||||
"fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
|
||||
"lookInContext": 1,
|
||||
"adminGroupID": 4,
|
||||
"betaServer": true}}],
|
||||
"servlet-mapping": {
|
||||
"cofaxCDS": "/",
|
||||
"cofaxEmail": "/cofaxutil/aemail/*",
|
||||
"cofaxAdmin": "/admin/*",
|
||||
"fileServlet": "/static/*",
|
||||
"cofaxTools": "/tools/*"},
|
||||
|
||||
"taglib": {
|
||||
"taglib-uri": "cofax.tld",
|
||||
"taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
|
@ -1,26 +1,26 @@
|
||||
{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
{"widget": {
|
||||
"debug": "on",
|
||||
"window": {
|
||||
"title": "Sample Konfabulator Widget",
|
||||
"name": "main_window",
|
||||
"width": 500,
|
||||
"height": 500
|
||||
},
|
||||
"image": {
|
||||
"src": "Images/Sun.png",
|
||||
"name": "sun1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 250,
|
||||
"alignment": "center"
|
||||
},
|
||||
"text": {
|
||||
"data": "Click Here",
|
||||
"size": 36,
|
||||
"style": "bold",
|
||||
"name": "text1",
|
||||
"hOffset": 250,
|
||||
"vOffset": 100,
|
||||
"alignment": "center",
|
||||
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
||||
}
|
||||
}}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"en":"I can eat glass and it doesn't hurt me.",
|
||||
"zh-Hant":"我能吞下玻璃而不傷身體。",
|
||||
"zh-Hans":"我能吞下玻璃而不伤身体。",
|
||||
"ja":"私はガラスを食べられます。それは私を傷つけません。",
|
||||
"ko":"나는 유리를 먹을 수 있어요. 그래도 아프지 않아요"
|
||||
{
|
||||
"en":"I can eat glass and it doesn't hurt me.",
|
||||
"zh-Hant":"我能吞下玻璃而不傷身體。",
|
||||
"zh-Hans":"我能吞下玻璃而不伤身体。",
|
||||
"ja":"私はガラスを食べられます。それは私を傷つけません。",
|
||||
"ko":"나는 유리를 먹을 수 있어요. 그래도 아프지 않아요"
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"en":"I can eat glass and it doesn't hurt me.",
|
||||
"zh-Hant":"我能吞下玻璃而不傷身體。",
|
||||
"zh-Hans":"我能吞下玻璃而不伤身体。",
|
||||
"ja":"私はガラスを食べられます。それは私を傷つけません。",
|
||||
"ko":"나는 유리를 먹을 수 있어요. 그래도 아프지 않아요"
|
||||
{
|
||||
"en":"I can eat glass and it doesn't hurt me.",
|
||||
"zh-Hant":"我能吞下玻璃而不傷身體。",
|
||||
"zh-Hans":"我能吞下玻璃而不伤身体。",
|
||||
"ja":"私はガラスを食べられます。それは私を傷つけません。",
|
||||
"ko":"나는 유리를 먹을 수 있어요. 그래도 아프지 않아요"
|
||||
}
|
@ -1,32 +1,32 @@
|
||||
// JSON condenser example
|
||||
|
||||
// This example parses JSON text from stdin with validation,
|
||||
// and re-output the JSON content to stdout without whitespace.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
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 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", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// JSON condenser example
|
||||
|
||||
// This example parses JSON text from stdin with validation,
|
||||
// and re-output the JSON content to stdout without whitespace.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
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 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", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,30 +1,30 @@
|
||||
// JSON pretty formatting example
|
||||
// This example can only handle UTF-8. For handling other encodings, see prettyauto example.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
int main(int, char*[]) {
|
||||
// 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);
|
||||
|
||||
// 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", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// JSON pretty formatting example
|
||||
// This example can only handle UTF-8. For handling other encodings, see prettyauto example.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
int main(int, char*[]) {
|
||||
// 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);
|
||||
|
||||
// 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", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,56 +1,56 @@
|
||||
// JSON pretty formatting example
|
||||
// This example can handle UTF-8/UTF-16LE/UTF-16BE/UTF-32LE/UTF-32BE.
|
||||
// The input firstly convert to UTF8, and then write to the original encoding with pretty formatting.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h" // NEW
|
||||
#include "rapidjson/error/en.h"
|
||||
#ifdef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
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
|
||||
#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 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
|
||||
#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
|
||||
#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", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// JSON pretty formatting example
|
||||
// This example can handle UTF-8/UTF-16LE/UTF-16BE/UTF-32LE/UTF-32BE.
|
||||
// The input firstly convert to UTF8, and then write to the original encoding with pretty formatting.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h" // NEW
|
||||
#include "rapidjson/error/en.h"
|
||||
#ifdef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
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
|
||||
#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 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
|
||||
#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
|
||||
#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", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,173 +1,173 @@
|
||||
// Serialize example
|
||||
// This example shows writing JSON string with writer directly.
|
||||
|
||||
#include "rapidjson/prettywriter.h" // for stringify JSON
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class Person {
|
||||
public:
|
||||
Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
|
||||
Person(const Person& rhs) : name_(rhs.name_), age_(rhs.age_) {}
|
||||
virtual ~Person();
|
||||
|
||||
Person& operator=(const Person& rhs) {
|
||||
name_ = rhs.name_;
|
||||
age_ = rhs.age_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
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");
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
writer.String(name_);
|
||||
#else
|
||||
writer.String(name_.c_str(), static_cast<SizeType>(name_.length())); // Supplying length of string is faster.
|
||||
#endif
|
||||
writer.String("age");
|
||||
writer.Uint(age_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
unsigned age_;
|
||||
};
|
||||
|
||||
Person::~Person() {
|
||||
}
|
||||
|
||||
class Education {
|
||||
public:
|
||||
Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
|
||||
Education(const Education& rhs) : school_(rhs.school_), GPA_(rhs.GPA_) {}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
writer.String("school");
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
writer.String(school_);
|
||||
#else
|
||||
writer.String(school_.c_str(), static_cast<SizeType>(school_.length()));
|
||||
#endif
|
||||
|
||||
writer.String("GPA");
|
||||
writer.Double(GPA_);
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
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& operator=(const Dependent& rhs) {
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
delete education_;
|
||||
education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
Person::Serialize(writer);
|
||||
|
||||
writer.String("education");
|
||||
if (education_)
|
||||
education_->Serialize(writer);
|
||||
else
|
||||
writer.Null();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Education *education_;
|
||||
};
|
||||
|
||||
Dependent::~Dependent() {
|
||||
delete education_;
|
||||
}
|
||||
|
||||
class Employee : public Person {
|
||||
public:
|
||||
Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {}
|
||||
Employee(const Employee& rhs) : Person(rhs), dependents_(rhs.dependents_), married_(rhs.married_) {}
|
||||
virtual ~Employee();
|
||||
|
||||
Employee& operator=(const Employee& rhs) {
|
||||
static_cast<Person&>(*this) = rhs;
|
||||
dependents_ = rhs.dependents_;
|
||||
married_ = rhs.married_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void AddDependent(const Dependent& dependent) {
|
||||
dependents_.push_back(dependent);
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
Person::Serialize(writer);
|
||||
|
||||
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.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Dependent> dependents_;
|
||||
bool married_;
|
||||
};
|
||||
|
||||
Employee::~Employee() {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
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("Percy TSE", 30, false));
|
||||
|
||||
StringBuffer sb;
|
||||
PrettyWriter<StringBuffer> writer(sb);
|
||||
|
||||
writer.StartArray();
|
||||
for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr)
|
||||
employeeItr->Serialize(writer);
|
||||
writer.EndArray();
|
||||
|
||||
puts(sb.GetString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
// Serialize example
|
||||
// This example shows writing JSON string with writer directly.
|
||||
|
||||
#include "rapidjson/prettywriter.h" // for stringify JSON
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class Person {
|
||||
public:
|
||||
Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
|
||||
Person(const Person& rhs) : name_(rhs.name_), age_(rhs.age_) {}
|
||||
virtual ~Person();
|
||||
|
||||
Person& operator=(const Person& rhs) {
|
||||
name_ = rhs.name_;
|
||||
age_ = rhs.age_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
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");
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
writer.String(name_);
|
||||
#else
|
||||
writer.String(name_.c_str(), static_cast<SizeType>(name_.length())); // Supplying length of string is faster.
|
||||
#endif
|
||||
writer.String("age");
|
||||
writer.Uint(age_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
unsigned age_;
|
||||
};
|
||||
|
||||
Person::~Person() {
|
||||
}
|
||||
|
||||
class Education {
|
||||
public:
|
||||
Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
|
||||
Education(const Education& rhs) : school_(rhs.school_), GPA_(rhs.GPA_) {}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
writer.String("school");
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
writer.String(school_);
|
||||
#else
|
||||
writer.String(school_.c_str(), static_cast<SizeType>(school_.length()));
|
||||
#endif
|
||||
|
||||
writer.String("GPA");
|
||||
writer.Double(GPA_);
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
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& operator=(const Dependent& rhs) {
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
delete education_;
|
||||
education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
Person::Serialize(writer);
|
||||
|
||||
writer.String("education");
|
||||
if (education_)
|
||||
education_->Serialize(writer);
|
||||
else
|
||||
writer.Null();
|
||||
|
||||
writer.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Education *education_;
|
||||
};
|
||||
|
||||
Dependent::~Dependent() {
|
||||
delete education_;
|
||||
}
|
||||
|
||||
class Employee : public Person {
|
||||
public:
|
||||
Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {}
|
||||
Employee(const Employee& rhs) : Person(rhs), dependents_(rhs.dependents_), married_(rhs.married_) {}
|
||||
virtual ~Employee();
|
||||
|
||||
Employee& operator=(const Employee& rhs) {
|
||||
static_cast<Person&>(*this) = rhs;
|
||||
dependents_ = rhs.dependents_;
|
||||
married_ = rhs.married_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void AddDependent(const Dependent& dependent) {
|
||||
dependents_.push_back(dependent);
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void Serialize(Writer& writer) const {
|
||||
writer.StartObject();
|
||||
|
||||
Person::Serialize(writer);
|
||||
|
||||
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.EndObject();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Dependent> dependents_;
|
||||
bool married_;
|
||||
};
|
||||
|
||||
Employee::~Employee() {
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
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("Percy TSE", 30, false));
|
||||
|
||||
StringBuffer sb;
|
||||
PrettyWriter<StringBuffer> writer(sb);
|
||||
|
||||
writer.StartArray();
|
||||
for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr)
|
||||
employeeItr->Serialize(writer);
|
||||
writer.EndArray();
|
||||
|
||||
puts(sb.GetString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,151 +1,151 @@
|
||||
// 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 <cstdio>
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
int main(int, char*[]) {
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
|
||||
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;
|
||||
#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;
|
||||
#endif
|
||||
|
||||
printf("\nParsing to document succeeded.\n");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 2. Access values in document.
|
||||
|
||||
printf("\nAccess values in document:\n");
|
||||
assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
|
||||
|
||||
assert(document.HasMember("hello"));
|
||||
assert(document["hello"].IsString());
|
||||
printf("hello = %s\n", document["hello"].GetString());
|
||||
|
||||
// Since version 0.2, you can use single lookup to check the existing of member and its value:
|
||||
Value::MemberIterator hello = document.FindMember("hello");
|
||||
assert(hello != document.MemberEnd());
|
||||
assert(hello->value.IsString());
|
||||
assert(strcmp("world", hello->value.GetString()) == 0);
|
||||
(void)hello;
|
||||
|
||||
assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
|
||||
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
|
||||
|
||||
assert(document["f"].IsBool());
|
||||
printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
|
||||
|
||||
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
|
||||
|
||||
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
|
||||
assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
|
||||
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
|
||||
|
||||
assert(document["pi"].IsNumber());
|
||||
assert(document["pi"].IsDouble());
|
||||
printf("pi = %g\n", document["pi"].GetDouble());
|
||||
|
||||
{
|
||||
const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
|
||||
assert(a.IsArray());
|
||||
for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
|
||||
printf("a[%d] = %d\n", i, a[i].GetInt());
|
||||
|
||||
int y = a[0].GetInt();
|
||||
(void)y;
|
||||
|
||||
// Iterating array with iterators
|
||||
printf("a = ");
|
||||
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
|
||||
printf("%d ", itr->GetInt());
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Iterating object members
|
||||
static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
|
||||
for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
|
||||
printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 3. Modify values in document.
|
||||
|
||||
// Change i to a bigger number
|
||||
{
|
||||
uint64_t f20 = 1; // compute factorial of 20
|
||||
for (uint64_t j = 1; j <= 20; j++)
|
||||
f20 *= j;
|
||||
document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
|
||||
assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
|
||||
}
|
||||
|
||||
// Adding values to array.
|
||||
{
|
||||
Value& a = document["a"]; // This time we uses non-const reference.
|
||||
Document::AllocatorType& allocator = document.GetAllocator();
|
||||
for (int i = 5; i <= 10; i++)
|
||||
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
|
||||
|
||||
// Fluent API
|
||||
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
|
||||
}
|
||||
|
||||
// Making string values.
|
||||
|
||||
// This version of SetString() just store the pointer to the string.
|
||||
// So it is for literal and string that exists within value's life-cycle.
|
||||
{
|
||||
document["hello"] = "rapidjson"; // This will invoke strlen()
|
||||
// Faster version:
|
||||
// document["hello"].SetString("rapidjson", 9);
|
||||
}
|
||||
|
||||
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
|
||||
Value author;
|
||||
{
|
||||
char buffer2[10];
|
||||
int len = sprintf(buffer2, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
||||
|
||||
author.SetString(buffer2, static_cast<SizeType>(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(buffer2, 0, sizeof(buffer2)); // For demonstration purpose.
|
||||
}
|
||||
// Variable 'buffer' is unusable now but 'author' has already made a copy.
|
||||
document.AddMember("author", author, document.GetAllocator());
|
||||
|
||||
assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 4. Stringify JSON
|
||||
|
||||
printf("\nModified JSON with reformatting:\n");
|
||||
StringBuffer sb;
|
||||
PrettyWriter<StringBuffer> writer(sb);
|
||||
document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
|
||||
puts(sb.GetString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
// 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 <cstdio>
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
int main(int, char*[]) {
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
|
||||
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;
|
||||
#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;
|
||||
#endif
|
||||
|
||||
printf("\nParsing to document succeeded.\n");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 2. Access values in document.
|
||||
|
||||
printf("\nAccess values in document:\n");
|
||||
assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
|
||||
|
||||
assert(document.HasMember("hello"));
|
||||
assert(document["hello"].IsString());
|
||||
printf("hello = %s\n", document["hello"].GetString());
|
||||
|
||||
// Since version 0.2, you can use single lookup to check the existing of member and its value:
|
||||
Value::MemberIterator hello = document.FindMember("hello");
|
||||
assert(hello != document.MemberEnd());
|
||||
assert(hello->value.IsString());
|
||||
assert(strcmp("world", hello->value.GetString()) == 0);
|
||||
(void)hello;
|
||||
|
||||
assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
|
||||
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
|
||||
|
||||
assert(document["f"].IsBool());
|
||||
printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
|
||||
|
||||
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
|
||||
|
||||
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
|
||||
assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
|
||||
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
|
||||
|
||||
assert(document["pi"].IsNumber());
|
||||
assert(document["pi"].IsDouble());
|
||||
printf("pi = %g\n", document["pi"].GetDouble());
|
||||
|
||||
{
|
||||
const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
|
||||
assert(a.IsArray());
|
||||
for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
|
||||
printf("a[%d] = %d\n", i, a[i].GetInt());
|
||||
|
||||
int y = a[0].GetInt();
|
||||
(void)y;
|
||||
|
||||
// Iterating array with iterators
|
||||
printf("a = ");
|
||||
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
|
||||
printf("%d ", itr->GetInt());
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Iterating object members
|
||||
static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
|
||||
for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
|
||||
printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 3. Modify values in document.
|
||||
|
||||
// Change i to a bigger number
|
||||
{
|
||||
uint64_t f20 = 1; // compute factorial of 20
|
||||
for (uint64_t j = 1; j <= 20; j++)
|
||||
f20 *= j;
|
||||
document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
|
||||
assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
|
||||
}
|
||||
|
||||
// Adding values to array.
|
||||
{
|
||||
Value& a = document["a"]; // This time we uses non-const reference.
|
||||
Document::AllocatorType& allocator = document.GetAllocator();
|
||||
for (int i = 5; i <= 10; i++)
|
||||
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
|
||||
|
||||
// Fluent API
|
||||
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
|
||||
}
|
||||
|
||||
// Making string values.
|
||||
|
||||
// This version of SetString() just store the pointer to the string.
|
||||
// So it is for literal and string that exists within value's life-cycle.
|
||||
{
|
||||
document["hello"] = "rapidjson"; // This will invoke strlen()
|
||||
// Faster version:
|
||||
// document["hello"].SetString("rapidjson", 9);
|
||||
}
|
||||
|
||||
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
|
||||
Value author;
|
||||
{
|
||||
char buffer2[10];
|
||||
int len = sprintf(buffer2, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
|
||||
|
||||
author.SetString(buffer2, static_cast<SizeType>(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(buffer2, 0, sizeof(buffer2)); // For demonstration purpose.
|
||||
}
|
||||
// Variable 'buffer' is unusable now but 'author' has already made a copy.
|
||||
document.AddMember("author", author, document.GetAllocator());
|
||||
|
||||
assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 4. Stringify JSON
|
||||
|
||||
printf("\nModified JSON with reformatting:\n");
|
||||
StringBuffer sb;
|
||||
PrettyWriter<StringBuffer> writer(sb);
|
||||
document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
|
||||
puts(sb.GetString());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,263 +1,263 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) {
|
||||
if (size) // behavior of malloc(0) is implementation defined.
|
||||
return std::malloc(size);
|
||||
else
|
||||
return NULL; // standardize to returning NULL.
|
||||
}
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
(void)originalSize;
|
||||
if (newSize == 0) {
|
||||
std::free(originalPtr);
|
||||
return NULL;
|
||||
}
|
||||
return std::realloc(originalPtr, newSize);
|
||||
}
|
||||
static void Free(void *ptr) { std::free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
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
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||
chunkHead_->size = 0; // Clear user buffer
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + 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);
|
||||
|
||||
if (newSize == 0)
|
||||
return NULL;
|
||||
|
||||
originalSize = RAPIDJSON_ALIGN(originalSize);
|
||||
newSize = RAPIDJSON_ALIGN(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
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.
|
||||
if (originalSize)
|
||||
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||
return newBuffer;
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
|
||||
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||
#define RAPIDJSON_ALLOCATORS_H_
|
||||
|
||||
#include "rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
|
||||
\code
|
||||
concept Allocator {
|
||||
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||
|
||||
// Allocate a memory block.
|
||||
// \param size of the memory block in bytes.
|
||||
// \returns pointer to the memory block.
|
||||
void* Malloc(size_t size);
|
||||
|
||||
// Resize a memory block.
|
||||
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||
// \param newSize the new size in bytes.
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||
|
||||
// Free a memory block.
|
||||
// \param pointer to the memory block. Null pointer is permitted.
|
||||
static void Free(void *ptr);
|
||||
};
|
||||
\endcode
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CrtAllocator
|
||||
|
||||
//! C-runtime library allocator.
|
||||
/*! This class is just wrapper for standard C library memory routines.
|
||||
\note implements Allocator concept
|
||||
*/
|
||||
class CrtAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = true;
|
||||
void* Malloc(size_t size) {
|
||||
if (size) // behavior of malloc(0) is implementation defined.
|
||||
return std::malloc(size);
|
||||
else
|
||||
return NULL; // standardize to returning NULL.
|
||||
}
|
||||
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||
(void)originalSize;
|
||||
if (newSize == 0) {
|
||||
std::free(originalPtr);
|
||||
return NULL;
|
||||
}
|
||||
return std::realloc(originalPtr, newSize);
|
||||
}
|
||||
static void Free(void *ptr) { std::free(ptr); }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MemoryPoolAllocator
|
||||
|
||||
//! Default memory allocator used by the parser and DOM.
|
||||
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||
|
||||
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||
|
||||
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||
|
||||
User may also supply a buffer as the first chunk.
|
||||
|
||||
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||
|
||||
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
|
||||
*/
|
||||
template <typename BaseAllocator = CrtAllocator>
|
||||
class MemoryPoolAllocator {
|
||||
public:
|
||||
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||
|
||||
//! Constructor with chunkSize.
|
||||
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! Constructor with user-supplied buffer.
|
||||
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||
|
||||
The user buffer will not be deallocated when this allocator is destructed.
|
||||
|
||||
\param buffer User supplied buffer.
|
||||
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||
\param baseAllocator The allocator for allocating memory chunks.
|
||||
*/
|
||||
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||
{
|
||||
RAPIDJSON_ASSERT(buffer != 0);
|
||||
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||
chunkHead_->size = 0;
|
||||
chunkHead_->next = 0;
|
||||
}
|
||||
|
||||
//! Destructor.
|
||||
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
*/
|
||||
~MemoryPoolAllocator() {
|
||||
Clear();
|
||||
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||
}
|
||||
|
||||
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||
void Clear() {
|
||||
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||
ChunkHeader* next = chunkHead_->next;
|
||||
baseAllocator_->Free(chunkHead_);
|
||||
chunkHead_ = next;
|
||||
}
|
||||
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||
chunkHead_->size = 0; // Clear user buffer
|
||||
}
|
||||
|
||||
//! Computes the total capacity of allocated memory chunks.
|
||||
/*! \return total capacity in bytes.
|
||||
*/
|
||||
size_t Capacity() const {
|
||||
size_t capacity = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
capacity += c->capacity;
|
||||
return capacity;
|
||||
}
|
||||
|
||||
//! Computes the memory blocks allocated.
|
||||
/*! \return total used bytes.
|
||||
*/
|
||||
size_t Size() const {
|
||||
size_t size = 0;
|
||||
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||
size += c->size;
|
||||
return size;
|
||||
}
|
||||
|
||||
//! Allocates a memory block. (concept Allocator)
|
||||
void* Malloc(size_t size) {
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
size = RAPIDJSON_ALIGN(size);
|
||||
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||
|
||||
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + 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);
|
||||
|
||||
if (newSize == 0)
|
||||
return NULL;
|
||||
|
||||
originalSize = RAPIDJSON_ALIGN(originalSize);
|
||||
newSize = RAPIDJSON_ALIGN(newSize);
|
||||
|
||||
// Do not shrink if new size is smaller than original
|
||||
if (originalSize >= newSize)
|
||||
return originalPtr;
|
||||
|
||||
// Simply expand it if it is the last allocation and there is sufficient space
|
||||
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||
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.
|
||||
if (originalSize)
|
||||
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||
return newBuffer;
|
||||
}
|
||||
|
||||
//! Frees a memory block (concept Allocator)
|
||||
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||
|
||||
private:
|
||||
//! Copy constructor is not permitted.
|
||||
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
//! Copy assignment operator is not permitted.
|
||||
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||
|
||||
//! Creates a new chunk.
|
||||
/*! \param capacity Capacity of the chunk in bytes.
|
||||
*/
|
||||
void AddChunk(size_t capacity) {
|
||||
if (!baseAllocator_)
|
||||
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
|
||||
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
|
||||
chunk->capacity = capacity;
|
||||
chunk->size = 0;
|
||||
chunk->next = chunkHead_;
|
||||
chunkHead_ = chunk;
|
||||
}
|
||||
|
||||
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||
|
||||
//! Chunk header for perpending to each chunk.
|
||||
/*! Chunks are stored as a singly linked list.
|
||||
*/
|
||||
struct ChunkHeader {
|
||||
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||
size_t size; //!< Current size of allocated memory in bytes.
|
||||
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||
};
|
||||
|
||||
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||
void *userBuffer_; //!< User supplied buffer.
|
||||
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_ENCODINGS_H_
|
||||
|
@ -1,295 +1,295 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "memorystream.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! 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.
|
||||
*/
|
||||
template <typename Encoding, typename InputByteStream>
|
||||
class EncodedInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
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(); }
|
||||
|
||||
// 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&);
|
||||
|
||||
InputByteStream& is_;
|
||||
Ch current_;
|
||||
};
|
||||
|
||||
//! Specialized for UTF8 MemoryStream.
|
||||
template <>
|
||||
class EncodedInputStream<UTF8<>, MemoryStream> {
|
||||
public:
|
||||
typedef UTF8<>::Ch Ch;
|
||||
|
||||
EncodedInputStream(MemoryStream& is) : is_(is) {
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
|
||||
}
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) {}
|
||||
void Flush() {}
|
||||
Ch* PutBegin() { return 0; }
|
||||
size_t PutEnd(Ch*) { return 0; }
|
||||
|
||||
MemoryStream& is_;
|
||||
};
|
||||
|
||||
//! Output byte stream wrapper with statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
class EncodedOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
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(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
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&);
|
||||
|
||||
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.
|
||||
*/
|
||||
template <typename CharType, typename InputByteStream>
|
||||
class AutoUTFInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
|
||||
if (!hasBOM_) {
|
||||
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
}
|
||||
|
||||
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 OutputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
class AutoUTFOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
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&);
|
||||
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
};
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "memorystream.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! 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.
|
||||
*/
|
||||
template <typename Encoding, typename InputByteStream>
|
||||
class EncodedInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
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(); }
|
||||
|
||||
// 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&);
|
||||
|
||||
InputByteStream& is_;
|
||||
Ch current_;
|
||||
};
|
||||
|
||||
//! Specialized for UTF8 MemoryStream.
|
||||
template <>
|
||||
class EncodedInputStream<UTF8<>, MemoryStream> {
|
||||
public:
|
||||
typedef UTF8<>::Ch Ch;
|
||||
|
||||
EncodedInputStream(MemoryStream& is) : is_(is) {
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
|
||||
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
|
||||
}
|
||||
Ch Peek() const { return is_.Peek(); }
|
||||
Ch Take() { return is_.Take(); }
|
||||
size_t Tell() const { return is_.Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) {}
|
||||
void Flush() {}
|
||||
Ch* PutBegin() { return 0; }
|
||||
size_t PutEnd(Ch*) { return 0; }
|
||||
|
||||
MemoryStream& is_;
|
||||
};
|
||||
|
||||
//! Output byte stream wrapper with statically bound encoding.
|
||||
/*!
|
||||
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||
*/
|
||||
template <typename Encoding, typename OutputByteStream>
|
||||
class EncodedOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
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(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
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&);
|
||||
|
||||
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.
|
||||
*/
|
||||
template <typename CharType, typename InputByteStream>
|
||||
class AutoUTFInputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param is input stream to be wrapped.
|
||||
\param type UTF encoding type if it is not detected from the stream.
|
||||
*/
|
||||
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
DetectType();
|
||||
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||
takeFunc_ = f[type_];
|
||||
current_ = takeFunc_(*is_);
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
bool HasBOM() const { return hasBOM_; }
|
||||
|
||||
Ch Peek() const { return current_; }
|
||||
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||
size_t Tell() const { return is_->Tell(); }
|
||||
|
||||
// Not implemented
|
||||
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||
|
||||
// Detect encoding type with BOM or RFC 4627
|
||||
void DetectType() {
|
||||
// BOM (Byte Order Mark):
|
||||
// 00 00 FE FF UTF-32BE
|
||||
// FF FE 00 00 UTF-32LE
|
||||
// FE FF UTF-16BE
|
||||
// FF FE UTF-16LE
|
||||
// EF BB BF UTF-8
|
||||
|
||||
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||
hasBOM_ = false;
|
||||
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||
|
||||
// RFC 4627: Section 3
|
||||
// "Since the first two characters of a JSON text will always be ASCII
|
||||
// characters [RFC0020], it is possible to determine whether an octet
|
||||
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||
// at the pattern of nulls in the first four octets."
|
||||
// 00 00 00 xx UTF-32BE
|
||||
// 00 xx 00 xx UTF-16BE
|
||||
// xx 00 00 00 UTF-32LE
|
||||
// xx 00 xx 00 UTF-16LE
|
||||
// xx xx xx xx UTF-8
|
||||
|
||||
if (!hasBOM_) {
|
||||
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||
switch (pattern) {
|
||||
case 0x08: type_ = kUTF32BE; break;
|
||||
case 0x0A: type_ = kUTF16BE; break;
|
||||
case 0x01: type_ = kUTF32LE; break;
|
||||
case 0x05: type_ = kUTF16LE; break;
|
||||
case 0x0F: type_ = kUTF8; break;
|
||||
default: break; // Use type defined by user.
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
}
|
||||
|
||||
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 OutputByteStream type of output byte stream to be wrapped.
|
||||
*/
|
||||
template <typename CharType, typename OutputByteStream>
|
||||
class AutoUTFOutputStream {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||
public:
|
||||
typedef CharType Ch;
|
||||
|
||||
//! Constructor.
|
||||
/*!
|
||||
\param os output stream to be wrapped.
|
||||
\param type UTF encoding type.
|
||||
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||
*/
|
||||
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||
|
||||
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||
|
||||
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||
putFunc_ = f[type_];
|
||||
|
||||
if (putBOM)
|
||||
PutBOM();
|
||||
}
|
||||
|
||||
UTFType GetType() const { return type_; }
|
||||
|
||||
void Put(Ch c) { putFunc_(*os_, c); }
|
||||
void Flush() { os_->Flush(); }
|
||||
|
||||
// Not implemented
|
||||
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||
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&);
|
||||
|
||||
void PutBOM() {
|
||||
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||
f[type_](*os_);
|
||||
}
|
||||
|
||||
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||
|
||||
OutputByteStream* os_;
|
||||
UTFType type_;
|
||||
PutFunc putFunc_;
|
||||
};
|
||||
|
||||
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,99 +1,99 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! File byte stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileReadStream {
|
||||
public:
|
||||
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(std::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_); }
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::FILE* fp_;
|
||||
Ch *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(padded)
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! File byte stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileReadStream {
|
||||
public:
|
||||
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(std::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_); }
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::FILE* fp_;
|
||||
Ch *buffer_;
|
||||
size_t bufferSize_;
|
||||
Ch *bufferLast_;
|
||||
Ch *current_;
|
||||
size_t readCount_;
|
||||
size_t count_; //!< Number of characters read
|
||||
bool eof_;
|
||||
};
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
|
@ -1,104 +1,104 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of C file stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
|
||||
*current_++ = c;
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
std::memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
std::memset(current_, c, n);
|
||||
current_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||
// failure deliberately ignored at this time
|
||||
// added to avoid warn_unused_result build errors
|
||||
}
|
||||
current_ = buffer_;
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
|
||||
std::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);
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Wrapper of C file stream for input using fread().
|
||||
/*!
|
||||
\note implements Stream concept
|
||||
*/
|
||||
class FileWriteStream {
|
||||
public:
|
||||
typedef char Ch; //!< Character type. Only support char.
|
||||
|
||||
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||
RAPIDJSON_ASSERT(fp_ != 0);
|
||||
}
|
||||
|
||||
void Put(char c) {
|
||||
if (current_ >= bufferEnd_)
|
||||
Flush();
|
||||
|
||||
*current_++ = c;
|
||||
}
|
||||
|
||||
void PutN(char c, size_t n) {
|
||||
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
while (n > avail) {
|
||||
std::memset(current_, c, avail);
|
||||
current_ += avail;
|
||||
Flush();
|
||||
n -= avail;
|
||||
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
std::memset(current_, c, n);
|
||||
current_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
if (current_ != buffer_) {
|
||||
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||
// failure deliberately ignored at this time
|
||||
// added to avoid warn_unused_result build errors
|
||||
}
|
||||
current_ = buffer_;
|
||||
}
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
FileWriteStream(const FileWriteStream&);
|
||||
FileWriteStream& operator=(const FileWriteStream&);
|
||||
|
||||
std::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);
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_FILESTREAM_H_
|
||||
|
@ -1,181 +1,181 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||
#define RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(6334)
|
||||
#endif
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
//@cond RAPIDJSON_INTERNAL
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||
template <typename T> struct Void { typedef void Type; };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BoolType, TrueType, FalseType
|
||||
//
|
||||
template <bool Cond> struct BoolType {
|
||||
static const bool Value = Cond;
|
||||
typedef BoolType Type;
|
||||
};
|
||||
typedef BoolType<true> TrueType;
|
||||
typedef BoolType<false> FalseType;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||
//
|
||||
|
||||
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||
|
||||
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||
template <> struct AndExprCond<true, true> : TrueType {};
|
||||
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||
template <> struct OrExprCond<false, false> : FalseType {};
|
||||
|
||||
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AddConst, MaybeAddConst, RemoveConst
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
template <typename T> struct RemoveConst { typedef T Type; };
|
||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||
//
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
template <typename T> struct IsConst<const T> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst
|
||||
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||
|
||||
template <typename T> struct IsPointer : FalseType {};
|
||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsBaseOf
|
||||
//
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||
|
||||
#else // simplified version adopted from Boost
|
||||
|
||||
template<typename B, typename D> struct IsBaseOfImpl {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||
|
||||
typedef char (&Yes)[1];
|
||||
typedef char (&No) [2];
|
||||
|
||||
template <typename T>
|
||||
static Yes Check(const D*, T);
|
||||
static No Check(const B*, int);
|
||||
|
||||
struct Host {
|
||||
operator const B*() const;
|
||||
operator const D*();
|
||||
};
|
||||
|
||||
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||
};
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||
|
||||
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EnableIf / DisableIf
|
||||
//
|
||||
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||
|
||||
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeTag {};
|
||||
template <typename T> struct RemoveSfinaeTag;
|
||||
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||
|
||||
#define RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_DISABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
//@endcond
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_META_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||
#define RAPIDJSON_INTERNAL_META_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
#if defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(6334)
|
||||
#endif
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
#include <type_traits>
|
||||
#endif
|
||||
|
||||
//@cond RAPIDJSON_INTERNAL
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||
template <typename T> struct Void { typedef void Type; };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BoolType, TrueType, FalseType
|
||||
//
|
||||
template <bool Cond> struct BoolType {
|
||||
static const bool Value = Cond;
|
||||
typedef BoolType Type;
|
||||
};
|
||||
typedef BoolType<true> TrueType;
|
||||
typedef BoolType<false> FalseType;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||
//
|
||||
|
||||
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||
|
||||
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||
template <> struct AndExprCond<true, true> : TrueType {};
|
||||
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||
template <> struct OrExprCond<false, false> : FalseType {};
|
||||
|
||||
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AddConst, MaybeAddConst, RemoveConst
|
||||
template <typename T> struct AddConst { typedef const T Type; };
|
||||
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||
template <typename T> struct RemoveConst { typedef T Type; };
|
||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||
//
|
||||
template <typename T, typename U> struct IsSame : FalseType {};
|
||||
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||
|
||||
template <typename T> struct IsConst : FalseType {};
|
||||
template <typename T> struct IsConst<const T> : TrueType {};
|
||||
|
||||
template <typename CT, typename T>
|
||||
struct IsMoreConst
|
||||
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||
|
||||
template <typename T> struct IsPointer : FalseType {};
|
||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IsBaseOf
|
||||
//
|
||||
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||
|
||||
#else // simplified version adopted from Boost
|
||||
|
||||
template<typename B, typename D> struct IsBaseOfImpl {
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||
|
||||
typedef char (&Yes)[1];
|
||||
typedef char (&No) [2];
|
||||
|
||||
template <typename T>
|
||||
static Yes Check(const D*, T);
|
||||
static No Check(const B*, int);
|
||||
|
||||
struct Host {
|
||||
operator const B*() const;
|
||||
operator const D*();
|
||||
};
|
||||
|
||||
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||
};
|
||||
|
||||
template <typename B, typename D> struct IsBaseOf
|
||||
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||
|
||||
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EnableIf / DisableIf
|
||||
//
|
||||
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||
|
||||
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||
|
||||
template <typename Condition, typename T = void>
|
||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||
|
||||
// SFINAE helpers
|
||||
struct SfinaeTag {};
|
||||
template <typename T> struct RemoveSfinaeTag;
|
||||
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||
|
||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||
|
||||
#define RAPIDJSON_ENABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_DISABLEIF(cond) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||
|
||||
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
//@endcond
|
||||
|
||||
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_META_H_
|
||||
|
@ -1,55 +1,55 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
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
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_POW10_
|
||||
#define RAPIDJSON_POW10_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
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
|
||||
*/
|
||||
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];
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_POW10_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,230 +1,230 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "swap.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack(Stack&& rhs)
|
||||
: allocator_(rhs.allocator_),
|
||||
ownAllocator_(rhs.ownAllocator_),
|
||||
stack_(rhs.stack_),
|
||||
stackTop_(rhs.stackTop_),
|
||||
stackEnd_(rhs.stackEnd_),
|
||||
initialCapacity_(rhs.initialCapacity_)
|
||||
{
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
~Stack() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack& operator=(Stack&& rhs) {
|
||||
if (&rhs != this)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
allocator_ = rhs.allocator_;
|
||||
ownAllocator_ = rhs.ownAllocator_;
|
||||
stack_ = rhs.stack_;
|
||||
stackTop_ = rhs.stackTop_;
|
||||
stackEnd_ = rhs.stackEnd_;
|
||||
initialCapacity_ = rhs.initialCapacity_;
|
||||
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||
internal::Swap(allocator_, rhs.allocator_);
|
||||
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||
internal::Swap(stack_, rhs.stack_);
|
||||
internal::Swap(stackTop_, rhs.stackTop_);
|
||||
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||
}
|
||||
|
||||
void Clear() { stackTop_ = stack_; }
|
||||
|
||||
void ShrinkToFit() {
|
||||
if (Empty()) {
|
||||
// If the stack is empty, completely deallocate the memory.
|
||||
Allocator::Free(stack_);
|
||||
stack_ = 0;
|
||||
stackTop_ = 0;
|
||||
stackEnd_ = 0;
|
||||
}
|
||||
else
|
||||
Resize(GetSize());
|
||||
}
|
||||
|
||||
// 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 void Reserve(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
|
||||
Expand<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||
Reserve<T>(count);
|
||||
return PushUnsafe<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
|
||||
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||
stackTop_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stackTop_ -= count * sizeof(T);
|
||||
return reinterpret_cast<T*>(stackTop_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* Top() const {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* End() { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
template<typename T>
|
||||
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
bool HasAllocator() const {
|
||||
return allocator_ != 0;
|
||||
}
|
||||
|
||||
Allocator& GetAllocator() {
|
||||
RAPIDJSON_ASSERT(allocator_);
|
||||
return *allocator_;
|
||||
}
|
||||
|
||||
bool Empty() const { return stackTop_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void Expand(size_t count) {
|
||||
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||
size_t newCapacity;
|
||||
if (stack_ == 0) {
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||
newCapacity = initialCapacity_;
|
||||
} else {
|
||||
newCapacity = GetCapacity();
|
||||
newCapacity += (newCapacity + 1) / 2;
|
||||
}
|
||||
size_t newSize = GetSize() + sizeof(T) * count;
|
||||
if (newCapacity < newSize)
|
||||
newCapacity = newSize;
|
||||
|
||||
Resize(newCapacity);
|
||||
}
|
||||
|
||||
void Resize(size_t newCapacity) {
|
||||
const size_t size = GetSize(); // Backup the current size
|
||||
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||
stackTop_ = stack_ + size;
|
||||
stackEnd_ = stack_ + newCapacity;
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
Allocator::Free(stack_);
|
||||
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* ownAllocator_;
|
||||
char *stack_;
|
||||
char *stackTop_;
|
||||
char *stackEnd_;
|
||||
size_t initialCapacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||
|
||||
#include "../allocators.h"
|
||||
#include "swap.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Stack
|
||||
|
||||
//! A type-unsafe stack for storing different types of data.
|
||||
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||
*/
|
||||
template <typename Allocator>
|
||||
class Stack {
|
||||
public:
|
||||
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack(Stack&& rhs)
|
||||
: allocator_(rhs.allocator_),
|
||||
ownAllocator_(rhs.ownAllocator_),
|
||||
stack_(rhs.stack_),
|
||||
stackTop_(rhs.stackTop_),
|
||||
stackEnd_(rhs.stackEnd_),
|
||||
initialCapacity_(rhs.initialCapacity_)
|
||||
{
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
~Stack() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
Stack& operator=(Stack&& rhs) {
|
||||
if (&rhs != this)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
allocator_ = rhs.allocator_;
|
||||
ownAllocator_ = rhs.ownAllocator_;
|
||||
stack_ = rhs.stack_;
|
||||
stackTop_ = rhs.stackTop_;
|
||||
stackEnd_ = rhs.stackEnd_;
|
||||
initialCapacity_ = rhs.initialCapacity_;
|
||||
|
||||
rhs.allocator_ = 0;
|
||||
rhs.ownAllocator_ = 0;
|
||||
rhs.stack_ = 0;
|
||||
rhs.stackTop_ = 0;
|
||||
rhs.stackEnd_ = 0;
|
||||
rhs.initialCapacity_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||
internal::Swap(allocator_, rhs.allocator_);
|
||||
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||
internal::Swap(stack_, rhs.stack_);
|
||||
internal::Swap(stackTop_, rhs.stackTop_);
|
||||
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||
}
|
||||
|
||||
void Clear() { stackTop_ = stack_; }
|
||||
|
||||
void ShrinkToFit() {
|
||||
if (Empty()) {
|
||||
// If the stack is empty, completely deallocate the memory.
|
||||
Allocator::Free(stack_);
|
||||
stack_ = 0;
|
||||
stackTop_ = 0;
|
||||
stackEnd_ = 0;
|
||||
}
|
||||
else
|
||||
Resize(GetSize());
|
||||
}
|
||||
|
||||
// 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 void Reserve(size_t count = 1) {
|
||||
// Expand the stack if needed
|
||||
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
|
||||
Expand<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||
Reserve<T>(count);
|
||||
return PushUnsafe<T>(count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
|
||||
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||
stackTop_ += sizeof(T) * count;
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Pop(size_t count) {
|
||||
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||
stackTop_ -= count * sizeof(T);
|
||||
return reinterpret_cast<T*>(stackTop_);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* Top() {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T* Top() const {
|
||||
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* End() { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
|
||||
|
||||
template<typename T>
|
||||
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
template<typename T>
|
||||
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
|
||||
|
||||
bool HasAllocator() const {
|
||||
return allocator_ != 0;
|
||||
}
|
||||
|
||||
Allocator& GetAllocator() {
|
||||
RAPIDJSON_ASSERT(allocator_);
|
||||
return *allocator_;
|
||||
}
|
||||
|
||||
bool Empty() const { return stackTop_ == stack_; }
|
||||
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void Expand(size_t count) {
|
||||
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||
size_t newCapacity;
|
||||
if (stack_ == 0) {
|
||||
if (!allocator_)
|
||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||
newCapacity = initialCapacity_;
|
||||
} else {
|
||||
newCapacity = GetCapacity();
|
||||
newCapacity += (newCapacity + 1) / 2;
|
||||
}
|
||||
size_t newSize = GetSize() + sizeof(T) * count;
|
||||
if (newCapacity < newSize)
|
||||
newCapacity = newSize;
|
||||
|
||||
Resize(newCapacity);
|
||||
}
|
||||
|
||||
void Resize(size_t newCapacity) {
|
||||
const size_t size = GetSize(); // Backup the current size
|
||||
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||
stackTop_ = stack_ + size;
|
||||
stackEnd_ = stack_ + newCapacity;
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
Allocator::Free(stack_);
|
||||
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||
}
|
||||
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
Stack(const Stack&);
|
||||
Stack& operator=(const Stack&);
|
||||
|
||||
Allocator* allocator_;
|
||||
Allocator* ownAllocator_;
|
||||
char *stack_;
|
||||
char *stackTop_;
|
||||
char *stackEnd_;
|
||||
size_t initialCapacity_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STACK_H_
|
||||
|
@ -1,55 +1,55 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
#include "../stream.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
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.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p) ++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
//! Returns number of code points in a encoded string.
|
||||
template<typename Encoding>
|
||||
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
const typename Encoding::Ch* end = s + length;
|
||||
SizeType count = 0;
|
||||
while (is.src_ < end) {
|
||||
unsigned codepoint;
|
||||
if (!Encoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
*outCount = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
||||
#include "../stream.h"
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
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.
|
||||
*/
|
||||
template <typename Ch>
|
||||
inline SizeType StrLen(const Ch* s) {
|
||||
const Ch* p = s;
|
||||
while (*p) ++p;
|
||||
return SizeType(p - s);
|
||||
}
|
||||
|
||||
//! Returns number of code points in a encoded string.
|
||||
template<typename Encoding>
|
||||
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||
GenericStringStream<Encoding> is(s);
|
||||
const typename Encoding::Ch* end = s + length;
|
||||
SizeType count = 0;
|
||||
while (is.src_ < end) {
|
||||
unsigned codepoint;
|
||||
if (!Encoding::Decode(is, &codepoint))
|
||||
return false;
|
||||
count++;
|
||||
}
|
||||
*outCount = count;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||
|
@ -1,46 +1,46 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
|
||||
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||
\note This has the same semantics as std::swap().
|
||||
*/
|
||||
template <typename T>
|
||||
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
|
||||
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||
|
||||
#include "../rapidjson.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||
\note This has the same semantics as std::swap().
|
||||
*/
|
||||
template <typename T>
|
||||
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,117 +1,117 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#include <utility> // std::move
|
||||
#endif
|
||||
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericStringBuffer {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
|
||||
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
|
||||
if (&rhs != this)
|
||||
stack_ = std::move(rhs.stack_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.ShrinkToFit();
|
||||
stack_.template Pop<Ch>(1);
|
||||
}
|
||||
|
||||
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<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);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
GenericStringBuffer(const GenericStringBuffer&);
|
||||
GenericStringBuffer& operator=(const GenericStringBuffer&);
|
||||
};
|
||||
|
||||
//! String buffer with UTF8 encoding
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
|
||||
stream.Reserve(count);
|
||||
}
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
|
||||
stream.PutUnsafe(c);
|
||||
}
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||
#define RAPIDJSON_STRINGBUFFER_H_
|
||||
|
||||
#include "stream.h"
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
#include <utility> // std::move
|
||||
#endif
|
||||
|
||||
#include "internal/stack.h"
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
RAPIDJSON_NAMESPACE_BEGIN
|
||||
|
||||
//! Represents an in-memory output stream.
|
||||
/*!
|
||||
\tparam Encoding Encoding of the stream.
|
||||
\tparam Allocator type for allocating memory buffer.
|
||||
\note implements Stream concept
|
||||
*/
|
||||
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||
class GenericStringBuffer {
|
||||
public:
|
||||
typedef typename Encoding::Ch Ch;
|
||||
|
||||
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
|
||||
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
|
||||
if (&rhs != this)
|
||||
stack_ = std::move(rhs.stack_);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
|
||||
void Flush() {}
|
||||
|
||||
void Clear() { stack_.Clear(); }
|
||||
void ShrinkToFit() {
|
||||
// Push and pop a null terminator. This is safe.
|
||||
*stack_.template Push<Ch>() = '\0';
|
||||
stack_.ShrinkToFit();
|
||||
stack_.template Pop<Ch>(1);
|
||||
}
|
||||
|
||||
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
|
||||
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<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);
|
||||
|
||||
return stack_.template Bottom<Ch>();
|
||||
}
|
||||
|
||||
size_t GetSize() const { return stack_.GetSize(); }
|
||||
|
||||
static const size_t kDefaultCapacity = 256;
|
||||
mutable internal::Stack<Allocator> stack_;
|
||||
|
||||
private:
|
||||
// Prohibit copy constructor & assignment operator.
|
||||
GenericStringBuffer(const GenericStringBuffer&);
|
||||
GenericStringBuffer& operator=(const GenericStringBuffer&);
|
||||
};
|
||||
|
||||
//! String buffer with UTF8 encoding
|
||||
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
|
||||
stream.Reserve(count);
|
||||
}
|
||||
|
||||
template<typename Encoding, typename Allocator>
|
||||
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
|
||||
stream.PutUnsafe(c);
|
||||
}
|
||||
|
||||
//! Implement specialized version of PutN() with memset() for better performance.
|
||||
template<>
|
||||
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||
}
|
||||
|
||||
RAPIDJSON_NAMESPACE_END
|
||||
|
||||
#if defined(__clang__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_STRINGBUFFER_H_
|
||||
|
114
license.txt
114
license.txt
@ -1,57 +1,57 @@
|
||||
Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
|
||||
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
|
||||
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
|
||||
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
|
||||
A copy of the MIT License is included in this file.
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
Open Source Software Licensed Under the BSD License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
The msinttypes r29
|
||||
Copyright (c) 2006-2013 Alexander Chemeris
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Open Source Software Licensed Under the JSON License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
json.org
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
JSON_checker
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
Terms of the JSON License:
|
||||
---------------------------------------------------
|
||||
|
||||
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 shall be used for Good, not Evil.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Terms of the MIT License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
|
||||
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
|
||||
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
|
||||
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
|
||||
A copy of the MIT License is included in this file.
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
Open Source Software Licensed Under the BSD License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
The msinttypes r29
|
||||
Copyright (c) 2006-2013 Alexander Chemeris
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Open Source Software Licensed Under the JSON License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
json.org
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
JSON_checker
|
||||
Copyright (c) 2002 JSON.org
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
Terms of the JSON License:
|
||||
---------------------------------------------------
|
||||
|
||||
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 shall be used for Good, not Evil.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Terms of the MIT License:
|
||||
--------------------------------------------------------------------
|
||||
|
||||
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.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#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);
|
||||
#endif
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#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);
|
||||
#endif
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
@ -1,182 +1,182 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef PERFTEST_H_
|
||||
#define PERFTEST_H_
|
||||
|
||||
#define TEST_RAPIDJSON 1
|
||||
#define TEST_PLATFORM 0
|
||||
#define TEST_MISC 0
|
||||
|
||||
#define TEST_VERSION_CODE(x,y,z) \
|
||||
(((x)*100000) + ((y)*100) + (z))
|
||||
|
||||
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
|
||||
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
|
||||
#if defined(__SSE4_2__)
|
||||
# define RAPIDJSON_SSE42
|
||||
#elif defined(__SSE2__)
|
||||
# define RAPIDJSON_SSE2
|
||||
#endif
|
||||
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Google Test
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
|
||||
#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#endif
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
#pragma warning(disable : 4996) // 'function': was declared deprecated
|
||||
#endif
|
||||
|
||||
//! Base class for all performance tests
|
||||
class PerfTest : public ::testing::Test {
|
||||
public:
|
||||
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
{
|
||||
const char *paths[] = {
|
||||
"data/sample.json",
|
||||
"bin/data/sample.json",
|
||||
"../bin/data/sample.json",
|
||||
"../../bin/data/sample.json",
|
||||
"../../../bin/data/sample.json"
|
||||
};
|
||||
|
||||
FILE *fp = 0;
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
fp = fopen(filename_ = paths[i], "rb");
|
||||
if (fp)
|
||||
break;
|
||||
}
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
ASSERT_EQ(length_, fread(json_, 1, length_, fp));
|
||||
json_[length_] = '\0';
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// whitespace test
|
||||
{
|
||||
whitespace_length_ = 1024 * 1024;
|
||||
whitespace_ = (char *)malloc(whitespace_length_ + 4);
|
||||
char *p = whitespace_;
|
||||
for (size_t i = 0; i < whitespace_length_; i += 4) {
|
||||
*p++ = ' ';
|
||||
*p++ = '\n';
|
||||
*p++ = '\r';
|
||||
*p++ = '\t';
|
||||
}
|
||||
*p++ = '[';
|
||||
*p++ = '0';
|
||||
*p++ = ']';
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
// types test
|
||||
{
|
||||
const char *typespaths[] = {
|
||||
"data/types",
|
||||
"bin/types",
|
||||
"../bin/types",
|
||||
"../../bin/types/",
|
||||
"../../../bin/types"
|
||||
};
|
||||
|
||||
const char* typesfilenames[] = {
|
||||
"booleans.json",
|
||||
"floats.json",
|
||||
"guids.json",
|
||||
"integers.json",
|
||||
"mixed.json",
|
||||
"nulls.json",
|
||||
"paragraphs.json"
|
||||
};
|
||||
|
||||
for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
|
||||
types_[j] = 0;
|
||||
for (size_t i = 0; i < sizeof(typespaths) / sizeof(typespaths[0]); i++) {
|
||||
char filename[256];
|
||||
sprintf(filename, "%s/%s", typespaths[i], typesfilenames[j]);
|
||||
if (FILE* fp = fopen(filename, "rb")) {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
typesLength_[j] = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
types_[j] = (char*)malloc(typesLength_[j] + 1);
|
||||
ASSERT_EQ(typesLength_[j], fread(types_[j], 1, typesLength_[j], fp));
|
||||
types_[j][typesLength_[j]] = '\0';
|
||||
fclose(fp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
free(whitespace_);
|
||||
json_ = 0;
|
||||
whitespace_ = 0;
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
free(types_[i]);
|
||||
types_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PerfTest(const PerfTest&);
|
||||
PerfTest& operator=(const PerfTest&);
|
||||
|
||||
protected:
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
char *whitespace_;
|
||||
size_t whitespace_length_;
|
||||
char *types_[7];
|
||||
size_t typesLength_[7];
|
||||
|
||||
static const size_t kTrialCount = 1000;
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // PERFTEST_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef PERFTEST_H_
|
||||
#define PERFTEST_H_
|
||||
|
||||
#define TEST_RAPIDJSON 1
|
||||
#define TEST_PLATFORM 0
|
||||
#define TEST_MISC 0
|
||||
|
||||
#define TEST_VERSION_CODE(x,y,z) \
|
||||
(((x)*100000) + ((y)*100) + (z))
|
||||
|
||||
// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
|
||||
// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
|
||||
#if defined(__SSE4_2__)
|
||||
# define RAPIDJSON_SSE42
|
||||
#elif defined(__SSE2__)
|
||||
# define RAPIDJSON_SSE2
|
||||
#endif
|
||||
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Google Test
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
|
||||
#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#endif
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
#pragma warning(disable : 4996) // 'function': was declared deprecated
|
||||
#endif
|
||||
|
||||
//! Base class for all performance tests
|
||||
class PerfTest : public ::testing::Test {
|
||||
public:
|
||||
PerfTest() : filename_(), json_(), length_(), whitespace_(), whitespace_length_() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
{
|
||||
const char *paths[] = {
|
||||
"data/sample.json",
|
||||
"bin/data/sample.json",
|
||||
"../bin/data/sample.json",
|
||||
"../../bin/data/sample.json",
|
||||
"../../../bin/data/sample.json"
|
||||
};
|
||||
|
||||
FILE *fp = 0;
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
fp = fopen(filename_ = paths[i], "rb");
|
||||
if (fp)
|
||||
break;
|
||||
}
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = (char*)malloc(length_ + 1);
|
||||
ASSERT_EQ(length_, fread(json_, 1, length_, fp));
|
||||
json_[length_] = '\0';
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// whitespace test
|
||||
{
|
||||
whitespace_length_ = 1024 * 1024;
|
||||
whitespace_ = (char *)malloc(whitespace_length_ + 4);
|
||||
char *p = whitespace_;
|
||||
for (size_t i = 0; i < whitespace_length_; i += 4) {
|
||||
*p++ = ' ';
|
||||
*p++ = '\n';
|
||||
*p++ = '\r';
|
||||
*p++ = '\t';
|
||||
}
|
||||
*p++ = '[';
|
||||
*p++ = '0';
|
||||
*p++ = ']';
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
// types test
|
||||
{
|
||||
const char *typespaths[] = {
|
||||
"data/types",
|
||||
"bin/types",
|
||||
"../bin/types",
|
||||
"../../bin/types/",
|
||||
"../../../bin/types"
|
||||
};
|
||||
|
||||
const char* typesfilenames[] = {
|
||||
"booleans.json",
|
||||
"floats.json",
|
||||
"guids.json",
|
||||
"integers.json",
|
||||
"mixed.json",
|
||||
"nulls.json",
|
||||
"paragraphs.json"
|
||||
};
|
||||
|
||||
for (size_t j = 0; j < sizeof(typesfilenames) / sizeof(typesfilenames[0]); j++) {
|
||||
types_[j] = 0;
|
||||
for (size_t i = 0; i < sizeof(typespaths) / sizeof(typespaths[0]); i++) {
|
||||
char filename[256];
|
||||
sprintf(filename, "%s/%s", typespaths[i], typesfilenames[j]);
|
||||
if (FILE* fp = fopen(filename, "rb")) {
|
||||
fseek(fp, 0, SEEK_END);
|
||||
typesLength_[j] = (size_t)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
types_[j] = (char*)malloc(typesLength_[j] + 1);
|
||||
ASSERT_EQ(typesLength_[j], fread(types_[j], 1, typesLength_[j], fp));
|
||||
types_[j][typesLength_[j]] = '\0';
|
||||
fclose(fp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
free(whitespace_);
|
||||
json_ = 0;
|
||||
whitespace_ = 0;
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
free(types_[i]);
|
||||
types_[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PerfTest(const PerfTest&);
|
||||
PerfTest& operator=(const PerfTest&);
|
||||
|
||||
protected:
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
char *whitespace_;
|
||||
size_t whitespace_length_;
|
||||
char *types_[7];
|
||||
size_t typesLength_[7];
|
||||
|
||||
static const size_t kTrialCount = 1000;
|
||||
};
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // PERFTEST_H_
|
||||
|
@ -1,166 +1,166 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
// This file is for giving the performance characteristics of the platform (compiler/OS/CPU).
|
||||
|
||||
#if TEST_PLATFORM
|
||||
|
||||
#include <cmath>
|
||||
#include <fcntl.h>
|
||||
|
||||
// Windows
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// UNIX
|
||||
#if defined(unix) || defined(__unix__) || defined(__unix)
|
||||
#include <unistd.h>
|
||||
#ifdef _POSIX_MAPPED_FILES
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class Platform : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
|
||||
// temp buffer for testing
|
||||
temp_ = (char *)malloc(length_ + 1);
|
||||
memcpy(temp_, json_, length_);
|
||||
checkSum_ = CheckSum();
|
||||
}
|
||||
|
||||
char CheckSum() {
|
||||
char c = 0;
|
||||
for (size_t i = 0; i < length_; ++i)
|
||||
c += temp_[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
free(temp_);
|
||||
}
|
||||
|
||||
protected:
|
||||
char *temp_;
|
||||
char checkSum_;
|
||||
};
|
||||
|
||||
TEST_F(Platform, 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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Platform, memcmp) {
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(Platform, Whitespace_strlen) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TEST_PLATFORM
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
// This file is for giving the performance characteristics of the platform (compiler/OS/CPU).
|
||||
|
||||
#if TEST_PLATFORM
|
||||
|
||||
#include <cmath>
|
||||
#include <fcntl.h>
|
||||
|
||||
// Windows
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// UNIX
|
||||
#if defined(unix) || defined(__unix__) || defined(__unix)
|
||||
#include <unistd.h>
|
||||
#ifdef _POSIX_MAPPED_FILES
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class Platform : public PerfTest {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
|
||||
// temp buffer for testing
|
||||
temp_ = (char *)malloc(length_ + 1);
|
||||
memcpy(temp_, json_, length_);
|
||||
checkSum_ = CheckSum();
|
||||
}
|
||||
|
||||
char CheckSum() {
|
||||
char c = 0;
|
||||
for (size_t i = 0; i < length_; ++i)
|
||||
c += temp_[i];
|
||||
return c;
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
free(temp_);
|
||||
}
|
||||
|
||||
protected:
|
||||
char *temp_;
|
||||
char checkSum_;
|
||||
};
|
||||
|
||||
TEST_F(Platform, 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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(Platform, memcmp) {
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(Platform, Whitespace_strlen) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TEST_PLATFORM
|
||||
|
@ -1,441 +1,441 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_RAPIDJSON
|
||||
|
||||
#include "rapidjson/rapidjson.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/memorystream.h"
|
||||
|
||||
#ifdef RAPIDJSON_SSE2
|
||||
#define SIMD_SUFFIX(name) name##_SSE2
|
||||
#elif defined(RAPIDJSON_SSE42)
|
||||
#define SIMD_SUFFIX(name) name##_SSE42
|
||||
#else
|
||||
#define SIMD_SUFFIX(name) name
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class RapidJson : public PerfTest {
|
||||
public:
|
||||
RapidJson() : temp_(), doc_() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
|
||||
// temp buffer for insitu parsing.
|
||||
temp_ = (char *)malloc(length_ + 1);
|
||||
|
||||
// Parse as a document
|
||||
EXPECT_FALSE(doc_.Parse(json_).HasParseError());
|
||||
|
||||
for (size_t i = 0; i < 7; i++)
|
||||
EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
free(temp_);
|
||||
}
|
||||
|
||||
private:
|
||||
RapidJson(const RapidJson&);
|
||||
RapidJson& operator=(const RapidJson&);
|
||||
|
||||
protected:
|
||||
char *temp_;
|
||||
Document doc_;
|
||||
Document typesDoc_[7];
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_TYPED(index, Name)\
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_##Name)) {\
|
||||
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||
StringStream s(types_[index]);\
|
||||
BaseReaderHandler<> h;\
|
||||
Reader reader;\
|
||||
EXPECT_TRUE(reader.Parse(s, h));\
|
||||
}\
|
||||
}\
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler_##Name)) {\
|
||||
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||
memcpy(temp_, types_[index], typesLength_[index] + 1);\
|
||||
InsituStringStream s(temp_);\
|
||||
BaseReaderHandler<> h;\
|
||||
Reader reader;\
|
||||
EXPECT_TRUE(reader.Parse<kParseInsituFlag>(s, h));\
|
||||
}\
|
||||
}
|
||||
|
||||
TEST_TYPED(0, Booleans)
|
||||
TEST_TYPED(1, Floats)
|
||||
TEST_TYPED(2, Guids)
|
||||
TEST_TYPED(3, Integers)
|
||||
TEST_TYPED(4, Mixed)
|
||||
TEST_TYPED(5, Nulls)
|
||||
TEST_TYPED(6, Paragraphs)
|
||||
|
||||
#undef TEST_TYPED
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FullPrecision)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
StringStream s(json_);
|
||||
BaseReaderHandler<> h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseFullPrecisionFlag>(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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParse_MemoryPoolAllocator)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
doc.Parse(json_);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseLength_MemoryPoolAllocator)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
doc.Parse(json_, length_);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseStdString_MemoryPoolAllocator)) {
|
||||
const std::string s(json_, length_);
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
doc.Parse(s);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseEncodedInputStream_MemoryStream)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
MemoryStream ms(json_, length_);
|
||||
EncodedInputStream<UTF8<>, MemoryStream> is(ms);
|
||||
Document doc;
|
||||
doc.ParseStream<0, UTF8<> >(is);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseAutoUTFInputStream_MemoryStream)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
MemoryStream ms(json_, length_);
|
||||
AutoUTFInputStream<unsigned, MemoryStream> is(ms);
|
||||
Document doc;
|
||||
doc.ParseStream<0, AutoUTF<unsigned> >(is);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t Traverse(const T& value) {
|
||||
size_t count = 1;
|
||||
switch(value.GetType()) {
|
||||
case kObjectType:
|
||||
for (typename T::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
|
||||
count++; // name
|
||||
count += Traverse(itr->value);
|
||||
}
|
||||
break;
|
||||
|
||||
case kArrayType:
|
||||
for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr)
|
||||
count += Traverse(*itr);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
struct ValueCounter : public BaseReaderHandler<> {
|
||||
ValueCounter() : count_(1) {} // root
|
||||
|
||||
bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; }
|
||||
bool EndArray(SizeType elementCount) { count_ += elementCount; return true; }
|
||||
|
||||
SizeType count_;
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
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_);
|
||||
}
|
||||
}
|
||||
|
||||
struct NullStream {
|
||||
typedef char Ch;
|
||||
|
||||
NullStream() /*: length_(0)*/ {}
|
||||
void Put(Ch) { /*++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;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(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;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_TYPED(index, Name)\
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(Writer_StringBuffer_##Name)) {\
|
||||
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||
StringBuffer s(0, 1024 * 1024);\
|
||||
Writer<StringBuffer> writer(s);\
|
||||
typesDoc_[index].Accept(writer);\
|
||||
const char* str = s.GetString();\
|
||||
(void)str;\
|
||||
}\
|
||||
}
|
||||
|
||||
TEST_TYPED(0, Booleans)
|
||||
TEST_TYPED(1, Floats)
|
||||
TEST_TYPED(2, Guids)
|
||||
TEST_TYPED(3, Integers)
|
||||
TEST_TYPED(4, Mixed)
|
||||
TEST_TYPED(5, Nulls)
|
||||
TEST_TYPED(6, Paragraphs)
|
||||
|
||||
#undef TEST_TYPED
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SkipWhitespace_Basic) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
rapidjson::StringStream s(whitespace_);
|
||||
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
||||
s.Take();
|
||||
ASSERT_EQ('[', s.Peek());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(SkipWhitespace)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
rapidjson::StringStream s(whitespace_);
|
||||
rapidjson::SkipWhitespace(s);
|
||||
ASSERT_EQ('[', s.Peek());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SkipWhitespace_strspn) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
const char* s = whitespace_ + std::strspn(whitespace_, " \t\r\n");
|
||||
ASSERT_EQ('[', *s);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, UTF8_Validate) {
|
||||
NullStream os;
|
||||
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
StringStream is(json_);
|
||||
bool result = true;
|
||||
while (is.Peek() != '\0')
|
||||
result &= UTF8<>::Validate(is, os);
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, StringBuffer) {
|
||||
StringBuffer sb;
|
||||
for (int i = 0; i < 32 * 1024 * 1024; i++)
|
||||
sb.Put(i & 0x7f);
|
||||
}
|
||||
|
||||
#endif // TEST_RAPIDJSON
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_RAPIDJSON
|
||||
|
||||
#include "rapidjson/rapidjson.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/memorystream.h"
|
||||
|
||||
#ifdef RAPIDJSON_SSE2
|
||||
#define SIMD_SUFFIX(name) name##_SSE2
|
||||
#elif defined(RAPIDJSON_SSE42)
|
||||
#define SIMD_SUFFIX(name) name##_SSE42
|
||||
#else
|
||||
#define SIMD_SUFFIX(name) name
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class RapidJson : public PerfTest {
|
||||
public:
|
||||
RapidJson() : temp_(), doc_() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
|
||||
// temp buffer for insitu parsing.
|
||||
temp_ = (char *)malloc(length_ + 1);
|
||||
|
||||
// Parse as a document
|
||||
EXPECT_FALSE(doc_.Parse(json_).HasParseError());
|
||||
|
||||
for (size_t i = 0; i < 7; i++)
|
||||
EXPECT_FALSE(typesDoc_[i].Parse(types_[i]).HasParseError());
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
free(temp_);
|
||||
}
|
||||
|
||||
private:
|
||||
RapidJson(const RapidJson&);
|
||||
RapidJson& operator=(const RapidJson&);
|
||||
|
||||
protected:
|
||||
char *temp_;
|
||||
Document doc_;
|
||||
Document typesDoc_[7];
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_TYPED(index, Name)\
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_##Name)) {\
|
||||
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||
StringStream s(types_[index]);\
|
||||
BaseReaderHandler<> h;\
|
||||
Reader reader;\
|
||||
EXPECT_TRUE(reader.Parse(s, h));\
|
||||
}\
|
||||
}\
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParseInsitu_DummyHandler_##Name)) {\
|
||||
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||
memcpy(temp_, types_[index], typesLength_[index] + 1);\
|
||||
InsituStringStream s(temp_);\
|
||||
BaseReaderHandler<> h;\
|
||||
Reader reader;\
|
||||
EXPECT_TRUE(reader.Parse<kParseInsituFlag>(s, h));\
|
||||
}\
|
||||
}
|
||||
|
||||
TEST_TYPED(0, Booleans)
|
||||
TEST_TYPED(1, Floats)
|
||||
TEST_TYPED(2, Guids)
|
||||
TEST_TYPED(3, Integers)
|
||||
TEST_TYPED(4, Mixed)
|
||||
TEST_TYPED(5, Nulls)
|
||||
TEST_TYPED(6, Paragraphs)
|
||||
|
||||
#undef TEST_TYPED
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FullPrecision)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
StringStream s(json_);
|
||||
BaseReaderHandler<> h;
|
||||
Reader reader;
|
||||
EXPECT_TRUE(reader.Parse<kParseFullPrecisionFlag>(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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParse_MemoryPoolAllocator)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
doc.Parse(json_);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseLength_MemoryPoolAllocator)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
doc.Parse(json_, length_);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseStdString_MemoryPoolAllocator)) {
|
||||
const std::string s(json_, length_);
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
Document doc;
|
||||
doc.Parse(s);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseEncodedInputStream_MemoryStream)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
MemoryStream ms(json_, length_);
|
||||
EncodedInputStream<UTF8<>, MemoryStream> is(ms);
|
||||
Document doc;
|
||||
doc.ParseStream<0, UTF8<> >(is);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(DocumentParseAutoUTFInputStream_MemoryStream)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
MemoryStream ms(json_, length_);
|
||||
AutoUTFInputStream<unsigned, MemoryStream> is(ms);
|
||||
Document doc;
|
||||
doc.ParseStream<0, AutoUTF<unsigned> >(is);
|
||||
ASSERT_TRUE(doc.IsObject());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t Traverse(const T& value) {
|
||||
size_t count = 1;
|
||||
switch(value.GetType()) {
|
||||
case kObjectType:
|
||||
for (typename T::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
|
||||
count++; // name
|
||||
count += Traverse(itr->value);
|
||||
}
|
||||
break;
|
||||
|
||||
case kArrayType:
|
||||
for (typename T::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr)
|
||||
count += Traverse(*itr);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
struct ValueCounter : public BaseReaderHandler<> {
|
||||
ValueCounter() : count_(1) {} // root
|
||||
|
||||
bool EndObject(SizeType memberCount) { count_ += memberCount * 2; return true; }
|
||||
bool EndArray(SizeType elementCount) { count_ += elementCount; return true; }
|
||||
|
||||
SizeType count_;
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
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_);
|
||||
}
|
||||
}
|
||||
|
||||
struct NullStream {
|
||||
typedef char Ch;
|
||||
|
||||
NullStream() /*: length_(0)*/ {}
|
||||
void Put(Ch) { /*++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;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(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;
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_TYPED(index, Name)\
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(Writer_StringBuffer_##Name)) {\
|
||||
for (size_t i = 0; i < kTrialCount * 10; i++) {\
|
||||
StringBuffer s(0, 1024 * 1024);\
|
||||
Writer<StringBuffer> writer(s);\
|
||||
typesDoc_[index].Accept(writer);\
|
||||
const char* str = s.GetString();\
|
||||
(void)str;\
|
||||
}\
|
||||
}
|
||||
|
||||
TEST_TYPED(0, Booleans)
|
||||
TEST_TYPED(1, Floats)
|
||||
TEST_TYPED(2, Guids)
|
||||
TEST_TYPED(3, Integers)
|
||||
TEST_TYPED(4, Mixed)
|
||||
TEST_TYPED(5, Nulls)
|
||||
TEST_TYPED(6, Paragraphs)
|
||||
|
||||
#undef TEST_TYPED
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SkipWhitespace_Basic) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
rapidjson::StringStream s(whitespace_);
|
||||
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
||||
s.Take();
|
||||
ASSERT_EQ('[', s.Peek());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SIMD_SUFFIX(SkipWhitespace)) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
rapidjson::StringStream s(whitespace_);
|
||||
rapidjson::SkipWhitespace(s);
|
||||
ASSERT_EQ('[', s.Peek());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, SkipWhitespace_strspn) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
const char* s = whitespace_ + std::strspn(whitespace_, " \t\r\n");
|
||||
ASSERT_EQ('[', *s);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, UTF8_Validate) {
|
||||
NullStream os;
|
||||
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
StringStream is(json_);
|
||||
bool result = true;
|
||||
while (is.Peek() != '\0')
|
||||
result &= UTF8<>::Validate(is, os);
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RapidJson, StringBuffer) {
|
||||
StringBuffer sb;
|
||||
for (int i = 0; i < 32 * 1024 * 1024; i++)
|
||||
sb.Put(i & 0x7f);
|
||||
}
|
||||
|
||||
#endif // TEST_RAPIDJSON
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,313 +1,313 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/memorystream.h"
|
||||
#include "rapidjson/memorybuffer.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class EncodedStreamTest : public ::testing::Test {
|
||||
public:
|
||||
EncodedStreamTest() : json_(), length_() {}
|
||||
virtual ~EncodedStreamTest();
|
||||
|
||||
virtual void SetUp() {
|
||||
json_ = ReadFile("utf8.json", true, &length_);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
json_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
EncodedStreamTest(const EncodedStreamTest&);
|
||||
EncodedStreamTest& operator=(const EncodedStreamTest&);
|
||||
|
||||
protected:
|
||||
static FILE* Open(const char* filename) {
|
||||
const char *paths[] = {
|
||||
"encodings",
|
||||
"bin/encodings",
|
||||
"../bin/encodings",
|
||||
"../../bin/encodings",
|
||||
"../../../bin/encodings"
|
||||
};
|
||||
char buffer[1024];
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
sprintf(buffer, "%s/%s", paths[i], filename);
|
||||
FILE *fp = fopen(buffer, "rb");
|
||||
if (fp)
|
||||
return fp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
*outLength = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* buffer = static_cast<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_);
|
||||
|
||||
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_);
|
||||
|
||||
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);
|
||||
EXPECT_EQ(size, eis.Tell());
|
||||
}
|
||||
}
|
||||
|
||||
void TestAutoUTFInputStream(const char *filename, bool expectHasBOM) {
|
||||
// Test FileReadStream
|
||||
{
|
||||
char buffer[16];
|
||||
FILE *fp = Open(filename);
|
||||
ASSERT_TRUE(fp != 0);
|
||||
FileReadStream fs(fp, buffer, sizeof(buffer));
|
||||
AutoUTFInputStream<unsigned, FileReadStream> eis(fs);
|
||||
EXPECT_EQ(expectHasBOM, eis.HasBOM());
|
||||
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);
|
||||
EXPECT_EQ(expectHasBOM, eis.HasBOM());
|
||||
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);
|
||||
EXPECT_EQ(size, eis.Tell());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FileEncoding, typename MemoryEncoding>
|
||||
void TestEncodedOutputStream(const char* expectedFilename, bool putBOM) {
|
||||
// Test FileWriteStream
|
||||
{
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void TestAutoUTFOutputStream(UTFType type, bool putBOM, const char *expectedFilename) {
|
||||
// Test FileWriteStream
|
||||
{
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char *json_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
EncodedStreamTest::~EncodedStreamTest() {}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
TEST_F(EncodedStreamTest, AutoUTFInputStream) {
|
||||
TestAutoUTFInputStream("utf8.json", false);
|
||||
TestAutoUTFInputStream("utf8bom.json", true);
|
||||
TestAutoUTFInputStream("utf16le.json", false);
|
||||
TestAutoUTFInputStream("utf16lebom.json",true);
|
||||
TestAutoUTFInputStream("utf16be.json", false);
|
||||
TestAutoUTFInputStream("utf16bebom.json",true);
|
||||
TestAutoUTFInputStream("utf32le.json", false);
|
||||
TestAutoUTFInputStream("utf32lebom.json",true);
|
||||
TestAutoUTFInputStream("utf32be.json", false);
|
||||
TestAutoUTFInputStream("utf32bebom.json", true);
|
||||
|
||||
{
|
||||
// Auto detection fail, use user defined UTF type
|
||||
const char json[] = "{ }";
|
||||
MemoryStream ms(json, sizeof(json));
|
||||
AutoUTFInputStream<unsigned, MemoryStream> eis(ms, kUTF8);
|
||||
EXPECT_FALSE(eis.HasBOM());
|
||||
EXPECT_EQ(kUTF8, eis.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/memorystream.h"
|
||||
#include "rapidjson/memorybuffer.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class EncodedStreamTest : public ::testing::Test {
|
||||
public:
|
||||
EncodedStreamTest() : json_(), length_() {}
|
||||
virtual ~EncodedStreamTest();
|
||||
|
||||
virtual void SetUp() {
|
||||
json_ = ReadFile("utf8.json", true, &length_);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
json_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
EncodedStreamTest(const EncodedStreamTest&);
|
||||
EncodedStreamTest& operator=(const EncodedStreamTest&);
|
||||
|
||||
protected:
|
||||
static FILE* Open(const char* filename) {
|
||||
const char *paths[] = {
|
||||
"encodings",
|
||||
"bin/encodings",
|
||||
"../bin/encodings",
|
||||
"../../bin/encodings",
|
||||
"../../../bin/encodings"
|
||||
};
|
||||
char buffer[1024];
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
sprintf(buffer, "%s/%s", paths[i], filename);
|
||||
FILE *fp = fopen(buffer, "rb");
|
||||
if (fp)
|
||||
return fp;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
*outLength = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* buffer = static_cast<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_);
|
||||
|
||||
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_);
|
||||
|
||||
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);
|
||||
EXPECT_EQ(size, eis.Tell());
|
||||
}
|
||||
}
|
||||
|
||||
void TestAutoUTFInputStream(const char *filename, bool expectHasBOM) {
|
||||
// Test FileReadStream
|
||||
{
|
||||
char buffer[16];
|
||||
FILE *fp = Open(filename);
|
||||
ASSERT_TRUE(fp != 0);
|
||||
FileReadStream fs(fp, buffer, sizeof(buffer));
|
||||
AutoUTFInputStream<unsigned, FileReadStream> eis(fs);
|
||||
EXPECT_EQ(expectHasBOM, eis.HasBOM());
|
||||
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);
|
||||
EXPECT_EQ(expectHasBOM, eis.HasBOM());
|
||||
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);
|
||||
EXPECT_EQ(size, eis.Tell());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename FileEncoding, typename MemoryEncoding>
|
||||
void TestEncodedOutputStream(const char* expectedFilename, bool putBOM) {
|
||||
// Test FileWriteStream
|
||||
{
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void TestAutoUTFOutputStream(UTFType type, bool putBOM, const char *expectedFilename) {
|
||||
// Test FileWriteStream
|
||||
{
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char *json_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
EncodedStreamTest::~EncodedStreamTest() {}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
TEST_F(EncodedStreamTest, AutoUTFInputStream) {
|
||||
TestAutoUTFInputStream("utf8.json", false);
|
||||
TestAutoUTFInputStream("utf8bom.json", true);
|
||||
TestAutoUTFInputStream("utf16le.json", false);
|
||||
TestAutoUTFInputStream("utf16lebom.json",true);
|
||||
TestAutoUTFInputStream("utf16be.json", false);
|
||||
TestAutoUTFInputStream("utf16bebom.json",true);
|
||||
TestAutoUTFInputStream("utf32le.json", false);
|
||||
TestAutoUTFInputStream("utf32lebom.json",true);
|
||||
TestAutoUTFInputStream("utf32be.json", false);
|
||||
TestAutoUTFInputStream("utf32bebom.json", true);
|
||||
|
||||
{
|
||||
// Auto detection fail, use user defined UTF type
|
||||
const char json[] = "{ }";
|
||||
MemoryStream ms(json, sizeof(json));
|
||||
AutoUTFInputStream<unsigned, MemoryStream> eis(ms, kUTF8);
|
||||
EXPECT_FALSE(eis.HasBOM());
|
||||
EXPECT_EQ(kUTF8, eis.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
@ -1,425 +1,425 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
// Verification of encoders/decoders with Hoehrmann's UTF8 decoder
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
|
||||
#define UTF8_ACCEPT 0u
|
||||
|
||||
static const unsigned char utf8d[] = {
|
||||
// The first part of the table maps bytes to character classes that
|
||||
// to reduce the size of the transition table and create bitmasks.
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
|
||||
// The second part is a transition table that maps a combination
|
||||
// of a state of the automaton and a character class to a state.
|
||||
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
|
||||
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
|
||||
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
|
||||
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
|
||||
12,36,12,12,12,12,12,12,12,12,12,12,
|
||||
};
|
||||
|
||||
static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) {
|
||||
unsigned type = utf8d[byte];
|
||||
|
||||
*codep = (*state != UTF8_ACCEPT) ?
|
||||
(byte & 0x3fu) | (*codep << 6) :
|
||||
(0xff >> type) & (byte);
|
||||
|
||||
*state = utf8d[256 + *state + type];
|
||||
return *state;
|
||||
}
|
||||
|
||||
//static bool IsUTF8(unsigned char* s) {
|
||||
// unsigned codepoint, state = 0;
|
||||
//
|
||||
// while (*s)
|
||||
// decode(&state, &codepoint, *s++);
|
||||
//
|
||||
// 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();
|
||||
|
||||
// Decode with Hoehrmann
|
||||
{
|
||||
unsigned decodedCodepoint = 0;
|
||||
unsigned state = 0;
|
||||
|
||||
unsigned decodedCount = 0;
|
||||
for (const char* s = encodedStr; *s; ++s)
|
||||
if (!decode(&state, &decodedCodepoint, static_cast<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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// 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, static_cast<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';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
// Verification of encoders/decoders with Hoehrmann's UTF8 decoder
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
|
||||
#define UTF8_ACCEPT 0u
|
||||
|
||||
static const unsigned char utf8d[] = {
|
||||
// The first part of the table maps bytes to character classes that
|
||||
// to reduce the size of the transition table and create bitmasks.
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
|
||||
// The second part is a transition table that maps a combination
|
||||
// of a state of the automaton and a character class to a state.
|
||||
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
|
||||
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
|
||||
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
|
||||
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
|
||||
12,36,12,12,12,12,12,12,12,12,12,12,
|
||||
};
|
||||
|
||||
static unsigned inline decode(unsigned* state, unsigned* codep, unsigned byte) {
|
||||
unsigned type = utf8d[byte];
|
||||
|
||||
*codep = (*state != UTF8_ACCEPT) ?
|
||||
(byte & 0x3fu) | (*codep << 6) :
|
||||
(0xff >> type) & (byte);
|
||||
|
||||
*state = utf8d[256 + *state + type];
|
||||
return *state;
|
||||
}
|
||||
|
||||
//static bool IsUTF8(unsigned char* s) {
|
||||
// unsigned codepoint, state = 0;
|
||||
//
|
||||
// while (*s)
|
||||
// decode(&state, &codepoint, *s++);
|
||||
//
|
||||
// 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();
|
||||
|
||||
// Decode with Hoehrmann
|
||||
{
|
||||
unsigned decodedCodepoint = 0;
|
||||
unsigned state = 0;
|
||||
|
||||
unsigned decodedCount = 0;
|
||||
for (const char* s = encodedStr; *s; ++s)
|
||||
if (!decode(&state, &decodedCodepoint, static_cast<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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// 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, static_cast<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';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,112 +1,112 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class FileStreamTest : public ::testing::Test {
|
||||
public:
|
||||
FileStreamTest() : filename_(), json_(), length_() {}
|
||||
virtual ~FileStreamTest();
|
||||
|
||||
virtual void SetUp() {
|
||||
const char *paths[] = {
|
||||
"data/sample.json",
|
||||
"bin/data/sample.json",
|
||||
"../bin/data/sample.json",
|
||||
"../../bin/data/sample.json",
|
||||
"../../../bin/data/sample.json"
|
||||
};
|
||||
FILE* fp = 0;
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
fp = fopen(paths[i], "rb");
|
||||
if (fp) {
|
||||
filename_ = paths[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = static_cast<char*>(malloc(length_ + 1));
|
||||
size_t readLength = fread(json_, 1, length_, fp);
|
||||
json_[readLength] = '\0';
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
json_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
FileStreamTest(const FileStreamTest&);
|
||||
FileStreamTest& operator=(const FileStreamTest&);
|
||||
|
||||
protected:
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
FileStreamTest::~FileStreamTest() {}
|
||||
|
||||
TEST_F(FileStreamTest, FileReadStream) {
|
||||
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());
|
||||
}
|
||||
|
||||
EXPECT_EQ(length_, s.Tell());
|
||||
EXPECT_EQ('\0', s.Peek());
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
TEST_F(FileStreamTest, FileWriteStream) {
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
|
||||
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));
|
||||
|
||||
for (size_t i = 0; i < length_; i++)
|
||||
EXPECT_EQ(json_[i], is.Take());
|
||||
|
||||
EXPECT_EQ(length_, is.Tell());
|
||||
fclose(fp);
|
||||
|
||||
//std::cout << filename << std::endl;
|
||||
remove(filename);
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
class FileStreamTest : public ::testing::Test {
|
||||
public:
|
||||
FileStreamTest() : filename_(), json_(), length_() {}
|
||||
virtual ~FileStreamTest();
|
||||
|
||||
virtual void SetUp() {
|
||||
const char *paths[] = {
|
||||
"data/sample.json",
|
||||
"bin/data/sample.json",
|
||||
"../bin/data/sample.json",
|
||||
"../../bin/data/sample.json",
|
||||
"../../../bin/data/sample.json"
|
||||
};
|
||||
FILE* fp = 0;
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
fp = fopen(paths[i], "rb");
|
||||
if (fp) {
|
||||
filename_ = paths[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_TRUE(fp != 0);
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length_ = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
json_ = static_cast<char*>(malloc(length_ + 1));
|
||||
size_t readLength = fread(json_, 1, length_, fp);
|
||||
json_[readLength] = '\0';
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
free(json_);
|
||||
json_ = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
FileStreamTest(const FileStreamTest&);
|
||||
FileStreamTest& operator=(const FileStreamTest&);
|
||||
|
||||
protected:
|
||||
const char* filename_;
|
||||
char *json_;
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
FileStreamTest::~FileStreamTest() {}
|
||||
|
||||
TEST_F(FileStreamTest, FileReadStream) {
|
||||
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());
|
||||
}
|
||||
|
||||
EXPECT_EQ(length_, s.Tell());
|
||||
EXPECT_EQ('\0', s.Peek());
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
TEST_F(FileStreamTest, FileWriteStream) {
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
|
||||
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));
|
||||
|
||||
for (size_t i = 0; i < length_; i++)
|
||||
EXPECT_EQ(json_[i], is.Take());
|
||||
|
||||
EXPECT_EQ(length_, is.Tell());
|
||||
fclose(fp);
|
||||
|
||||
//std::cout << filename << std::endl;
|
||||
remove(filename);
|
||||
}
|
||||
|
@ -1,227 +1,227 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
// Using forward declared types here.
|
||||
|
||||
#include "rapidjson/fwd.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct Foo {
|
||||
Foo();
|
||||
~Foo();
|
||||
|
||||
// encodings.h
|
||||
UTF8<char>* utf8;
|
||||
UTF16<wchar_t>* utf16;
|
||||
UTF16BE<wchar_t>* utf16be;
|
||||
UTF16LE<wchar_t>* utf16le;
|
||||
UTF32<unsigned>* utf32;
|
||||
UTF32BE<unsigned>* utf32be;
|
||||
UTF32LE<unsigned>* utf32le;
|
||||
ASCII<char>* ascii;
|
||||
AutoUTF<unsigned>* autoutf;
|
||||
Transcoder<UTF8<char>, UTF8<char> >* transcoder;
|
||||
|
||||
// allocators.h
|
||||
CrtAllocator* crtallocator;
|
||||
MemoryPoolAllocator<CrtAllocator>* memorypoolallocator;
|
||||
|
||||
// stream.h
|
||||
StringStream* stringstream;
|
||||
InsituStringStream* insitustringstream;
|
||||
|
||||
// stringbuffer.h
|
||||
StringBuffer* stringbuffer;
|
||||
|
||||
// // filereadstream.h
|
||||
// FileReadStream* filereadstream;
|
||||
|
||||
// // filewritestream.h
|
||||
// FileWriteStream* filewritestream;
|
||||
|
||||
// memorybuffer.h
|
||||
MemoryBuffer* memorybuffer;
|
||||
|
||||
// memorystream.h
|
||||
MemoryStream* memorystream;
|
||||
|
||||
// reader.h
|
||||
BaseReaderHandler<UTF8<char>, void>* basereaderhandler;
|
||||
Reader* reader;
|
||||
|
||||
// writer.h
|
||||
Writer<StringBuffer, UTF8<char>, UTF8<char>, CrtAllocator, 0>* writer;
|
||||
|
||||
// prettywriter.h
|
||||
PrettyWriter<StringBuffer, UTF8<char>, UTF8<char>, CrtAllocator, 0>* prettywriter;
|
||||
|
||||
// document.h
|
||||
Value* value;
|
||||
Document* document;
|
||||
|
||||
// pointer.h
|
||||
Pointer* pointer;
|
||||
|
||||
// schema.h
|
||||
SchemaDocument* schemadocument;
|
||||
SchemaValidator* schemavalidator;
|
||||
|
||||
// char buffer[16];
|
||||
};
|
||||
|
||||
// Using type definitions here.
|
||||
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/memorybuffer.h"
|
||||
#include "rapidjson/memorystream.h"
|
||||
#include "rapidjson/document.h" // -> reader.h
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/schema.h" // -> pointer.h
|
||||
|
||||
Foo::Foo() :
|
||||
// encodings.h
|
||||
utf8(RAPIDJSON_NEW(UTF8<>)),
|
||||
utf16(RAPIDJSON_NEW(UTF16<>)),
|
||||
utf16be(RAPIDJSON_NEW(UTF16BE<>)),
|
||||
utf16le(RAPIDJSON_NEW(UTF16LE<>)),
|
||||
utf32(RAPIDJSON_NEW(UTF32<>)),
|
||||
utf32be(RAPIDJSON_NEW(UTF32BE<>)),
|
||||
utf32le(RAPIDJSON_NEW(UTF32LE<>)),
|
||||
ascii(RAPIDJSON_NEW(ASCII<>)),
|
||||
autoutf(RAPIDJSON_NEW(AutoUTF<unsigned>)),
|
||||
transcoder(RAPIDJSON_NEW((Transcoder<UTF8<>, UTF8<> >))),
|
||||
|
||||
// allocators.h
|
||||
crtallocator(RAPIDJSON_NEW(CrtAllocator)),
|
||||
memorypoolallocator(RAPIDJSON_NEW(MemoryPoolAllocator<>)),
|
||||
|
||||
// stream.h
|
||||
stringstream(RAPIDJSON_NEW(StringStream(0))),
|
||||
insitustringstream(RAPIDJSON_NEW(InsituStringStream(0))),
|
||||
|
||||
// stringbuffer.h
|
||||
stringbuffer(RAPIDJSON_NEW(StringBuffer)),
|
||||
|
||||
// // filereadstream.h
|
||||
// filereadstream(RAPIDJSON_NEW(FileReadStream(stdout, buffer, sizeof(buffer)))),
|
||||
|
||||
// // filewritestream.h
|
||||
// filewritestream(RAPIDJSON_NEW(FileWriteStream(stdout, buffer, sizeof(buffer)))),
|
||||
|
||||
// memorybuffer.h
|
||||
memorybuffer(RAPIDJSON_NEW(MemoryBuffer)),
|
||||
|
||||
// memorystream.h
|
||||
memorystream(RAPIDJSON_NEW(MemoryStream(0, 0))),
|
||||
|
||||
// reader.h
|
||||
basereaderhandler(RAPIDJSON_NEW((BaseReaderHandler<UTF8<>, void>))),
|
||||
reader(RAPIDJSON_NEW(Reader)),
|
||||
|
||||
// writer.h
|
||||
writer(RAPIDJSON_NEW((Writer<StringBuffer>))),
|
||||
|
||||
// prettywriter.h
|
||||
prettywriter(RAPIDJSON_NEW((PrettyWriter<StringBuffer>))),
|
||||
|
||||
// document.h
|
||||
value(RAPIDJSON_NEW(Value)),
|
||||
document(RAPIDJSON_NEW(Document)),
|
||||
|
||||
// pointer.h
|
||||
pointer(RAPIDJSON_NEW(Pointer)),
|
||||
|
||||
// schema.h
|
||||
schemadocument(RAPIDJSON_NEW(SchemaDocument(*document))),
|
||||
schemavalidator(RAPIDJSON_NEW(SchemaValidator(*schemadocument)))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Foo::~Foo() {
|
||||
// encodings.h
|
||||
RAPIDJSON_DELETE(utf8);
|
||||
RAPIDJSON_DELETE(utf16);
|
||||
RAPIDJSON_DELETE(utf16be);
|
||||
RAPIDJSON_DELETE(utf16le);
|
||||
RAPIDJSON_DELETE(utf32);
|
||||
RAPIDJSON_DELETE(utf32be);
|
||||
RAPIDJSON_DELETE(utf32le);
|
||||
RAPIDJSON_DELETE(ascii);
|
||||
RAPIDJSON_DELETE(autoutf);
|
||||
RAPIDJSON_DELETE(transcoder);
|
||||
|
||||
// allocators.h
|
||||
RAPIDJSON_DELETE(crtallocator);
|
||||
RAPIDJSON_DELETE(memorypoolallocator);
|
||||
|
||||
// stream.h
|
||||
RAPIDJSON_DELETE(stringstream);
|
||||
RAPIDJSON_DELETE(insitustringstream);
|
||||
|
||||
// stringbuffer.h
|
||||
RAPIDJSON_DELETE(stringbuffer);
|
||||
|
||||
// // filereadstream.h
|
||||
// RAPIDJSON_DELETE(filereadstream);
|
||||
|
||||
// // filewritestream.h
|
||||
// RAPIDJSON_DELETE(filewritestream);
|
||||
|
||||
// memorybuffer.h
|
||||
RAPIDJSON_DELETE(memorybuffer);
|
||||
|
||||
// memorystream.h
|
||||
RAPIDJSON_DELETE(memorystream);
|
||||
|
||||
// reader.h
|
||||
RAPIDJSON_DELETE(basereaderhandler);
|
||||
RAPIDJSON_DELETE(reader);
|
||||
|
||||
// writer.h
|
||||
RAPIDJSON_DELETE(writer);
|
||||
|
||||
// prettywriter.h
|
||||
RAPIDJSON_DELETE(prettywriter);
|
||||
|
||||
// document.h
|
||||
RAPIDJSON_DELETE(value);
|
||||
RAPIDJSON_DELETE(document);
|
||||
|
||||
// pointer.h
|
||||
RAPIDJSON_DELETE(pointer);
|
||||
|
||||
// schema.h
|
||||
RAPIDJSON_DELETE(schemadocument);
|
||||
RAPIDJSON_DELETE(schemavalidator);
|
||||
}
|
||||
|
||||
TEST(Fwd, Fwd) {
|
||||
Foo f;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
// Using forward declared types here.
|
||||
|
||||
#include "rapidjson/fwd.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
struct Foo {
|
||||
Foo();
|
||||
~Foo();
|
||||
|
||||
// encodings.h
|
||||
UTF8<char>* utf8;
|
||||
UTF16<wchar_t>* utf16;
|
||||
UTF16BE<wchar_t>* utf16be;
|
||||
UTF16LE<wchar_t>* utf16le;
|
||||
UTF32<unsigned>* utf32;
|
||||
UTF32BE<unsigned>* utf32be;
|
||||
UTF32LE<unsigned>* utf32le;
|
||||
ASCII<char>* ascii;
|
||||
AutoUTF<unsigned>* autoutf;
|
||||
Transcoder<UTF8<char>, UTF8<char> >* transcoder;
|
||||
|
||||
// allocators.h
|
||||
CrtAllocator* crtallocator;
|
||||
MemoryPoolAllocator<CrtAllocator>* memorypoolallocator;
|
||||
|
||||
// stream.h
|
||||
StringStream* stringstream;
|
||||
InsituStringStream* insitustringstream;
|
||||
|
||||
// stringbuffer.h
|
||||
StringBuffer* stringbuffer;
|
||||
|
||||
// // filereadstream.h
|
||||
// FileReadStream* filereadstream;
|
||||
|
||||
// // filewritestream.h
|
||||
// FileWriteStream* filewritestream;
|
||||
|
||||
// memorybuffer.h
|
||||
MemoryBuffer* memorybuffer;
|
||||
|
||||
// memorystream.h
|
||||
MemoryStream* memorystream;
|
||||
|
||||
// reader.h
|
||||
BaseReaderHandler<UTF8<char>, void>* basereaderhandler;
|
||||
Reader* reader;
|
||||
|
||||
// writer.h
|
||||
Writer<StringBuffer, UTF8<char>, UTF8<char>, CrtAllocator, 0>* writer;
|
||||
|
||||
// prettywriter.h
|
||||
PrettyWriter<StringBuffer, UTF8<char>, UTF8<char>, CrtAllocator, 0>* prettywriter;
|
||||
|
||||
// document.h
|
||||
Value* value;
|
||||
Document* document;
|
||||
|
||||
// pointer.h
|
||||
Pointer* pointer;
|
||||
|
||||
// schema.h
|
||||
SchemaDocument* schemadocument;
|
||||
SchemaValidator* schemavalidator;
|
||||
|
||||
// char buffer[16];
|
||||
};
|
||||
|
||||
// Using type definitions here.
|
||||
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/memorybuffer.h"
|
||||
#include "rapidjson/memorystream.h"
|
||||
#include "rapidjson/document.h" // -> reader.h
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/schema.h" // -> pointer.h
|
||||
|
||||
Foo::Foo() :
|
||||
// encodings.h
|
||||
utf8(RAPIDJSON_NEW(UTF8<>)),
|
||||
utf16(RAPIDJSON_NEW(UTF16<>)),
|
||||
utf16be(RAPIDJSON_NEW(UTF16BE<>)),
|
||||
utf16le(RAPIDJSON_NEW(UTF16LE<>)),
|
||||
utf32(RAPIDJSON_NEW(UTF32<>)),
|
||||
utf32be(RAPIDJSON_NEW(UTF32BE<>)),
|
||||
utf32le(RAPIDJSON_NEW(UTF32LE<>)),
|
||||
ascii(RAPIDJSON_NEW(ASCII<>)),
|
||||
autoutf(RAPIDJSON_NEW(AutoUTF<unsigned>)),
|
||||
transcoder(RAPIDJSON_NEW((Transcoder<UTF8<>, UTF8<> >))),
|
||||
|
||||
// allocators.h
|
||||
crtallocator(RAPIDJSON_NEW(CrtAllocator)),
|
||||
memorypoolallocator(RAPIDJSON_NEW(MemoryPoolAllocator<>)),
|
||||
|
||||
// stream.h
|
||||
stringstream(RAPIDJSON_NEW(StringStream(0))),
|
||||
insitustringstream(RAPIDJSON_NEW(InsituStringStream(0))),
|
||||
|
||||
// stringbuffer.h
|
||||
stringbuffer(RAPIDJSON_NEW(StringBuffer)),
|
||||
|
||||
// // filereadstream.h
|
||||
// filereadstream(RAPIDJSON_NEW(FileReadStream(stdout, buffer, sizeof(buffer)))),
|
||||
|
||||
// // filewritestream.h
|
||||
// filewritestream(RAPIDJSON_NEW(FileWriteStream(stdout, buffer, sizeof(buffer)))),
|
||||
|
||||
// memorybuffer.h
|
||||
memorybuffer(RAPIDJSON_NEW(MemoryBuffer)),
|
||||
|
||||
// memorystream.h
|
||||
memorystream(RAPIDJSON_NEW(MemoryStream(0, 0))),
|
||||
|
||||
// reader.h
|
||||
basereaderhandler(RAPIDJSON_NEW((BaseReaderHandler<UTF8<>, void>))),
|
||||
reader(RAPIDJSON_NEW(Reader)),
|
||||
|
||||
// writer.h
|
||||
writer(RAPIDJSON_NEW((Writer<StringBuffer>))),
|
||||
|
||||
// prettywriter.h
|
||||
prettywriter(RAPIDJSON_NEW((PrettyWriter<StringBuffer>))),
|
||||
|
||||
// document.h
|
||||
value(RAPIDJSON_NEW(Value)),
|
||||
document(RAPIDJSON_NEW(Document)),
|
||||
|
||||
// pointer.h
|
||||
pointer(RAPIDJSON_NEW(Pointer)),
|
||||
|
||||
// schema.h
|
||||
schemadocument(RAPIDJSON_NEW(SchemaDocument(*document))),
|
||||
schemavalidator(RAPIDJSON_NEW(SchemaValidator(*schemadocument)))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Foo::~Foo() {
|
||||
// encodings.h
|
||||
RAPIDJSON_DELETE(utf8);
|
||||
RAPIDJSON_DELETE(utf16);
|
||||
RAPIDJSON_DELETE(utf16be);
|
||||
RAPIDJSON_DELETE(utf16le);
|
||||
RAPIDJSON_DELETE(utf32);
|
||||
RAPIDJSON_DELETE(utf32be);
|
||||
RAPIDJSON_DELETE(utf32le);
|
||||
RAPIDJSON_DELETE(ascii);
|
||||
RAPIDJSON_DELETE(autoutf);
|
||||
RAPIDJSON_DELETE(transcoder);
|
||||
|
||||
// allocators.h
|
||||
RAPIDJSON_DELETE(crtallocator);
|
||||
RAPIDJSON_DELETE(memorypoolallocator);
|
||||
|
||||
// stream.h
|
||||
RAPIDJSON_DELETE(stringstream);
|
||||
RAPIDJSON_DELETE(insitustringstream);
|
||||
|
||||
// stringbuffer.h
|
||||
RAPIDJSON_DELETE(stringbuffer);
|
||||
|
||||
// // filereadstream.h
|
||||
// RAPIDJSON_DELETE(filereadstream);
|
||||
|
||||
// // filewritestream.h
|
||||
// RAPIDJSON_DELETE(filewritestream);
|
||||
|
||||
// memorybuffer.h
|
||||
RAPIDJSON_DELETE(memorybuffer);
|
||||
|
||||
// memorystream.h
|
||||
RAPIDJSON_DELETE(memorystream);
|
||||
|
||||
// reader.h
|
||||
RAPIDJSON_DELETE(basereaderhandler);
|
||||
RAPIDJSON_DELETE(reader);
|
||||
|
||||
// writer.h
|
||||
RAPIDJSON_DELETE(writer);
|
||||
|
||||
// prettywriter.h
|
||||
RAPIDJSON_DELETE(prettywriter);
|
||||
|
||||
// document.h
|
||||
RAPIDJSON_DELETE(value);
|
||||
RAPIDJSON_DELETE(document);
|
||||
|
||||
// pointer.h
|
||||
RAPIDJSON_DELETE(pointer);
|
||||
|
||||
// schema.h
|
||||
RAPIDJSON_DELETE(schemadocument);
|
||||
RAPIDJSON_DELETE(schemavalidator);
|
||||
}
|
||||
|
||||
TEST(Fwd, Fwd) {
|
||||
Foo f;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
@ -1,99 +1,99 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
static char* ReadFile(const char* filename, size_t& length) {
|
||||
const char *paths[] = {
|
||||
"jsonchecker",
|
||||
"bin/jsonchecker",
|
||||
"../bin/jsonchecker",
|
||||
"../../bin/jsonchecker",
|
||||
"../../../bin/jsonchecker"
|
||||
};
|
||||
char buffer[1024];
|
||||
FILE *fp = 0;
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
sprintf(buffer, "%s/%s", paths[i], filename);
|
||||
fp = fopen(buffer, "rb");
|
||||
if (fp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* json = static_cast<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];
|
||||
|
||||
// jsonchecker/failXX.json
|
||||
for (int i = 1; i <= 33; i++) {
|
||||
if (i == 1) // fail1.json is valid in rapidjson, which has no limitation on type of root element (RFC 7159).
|
||||
continue;
|
||||
if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting.
|
||||
continue;
|
||||
|
||||
sprintf(filename, "fail%d.json", i);
|
||||
size_t length;
|
||||
char* json = ReadFile(filename, length);
|
||||
if (!json) {
|
||||
printf("jsonchecker file %s not found", filename);
|
||||
ADD_FAILURE();
|
||||
continue;
|
||||
}
|
||||
|
||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
document.Parse(json);
|
||||
EXPECT_TRUE(document.HasParseError());
|
||||
|
||||
document.Parse<kParseIterativeFlag>(json);
|
||||
EXPECT_TRUE(document.HasParseError());
|
||||
|
||||
free(json);
|
||||
}
|
||||
|
||||
// passX.json
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
sprintf(filename, "pass%d.json", i);
|
||||
size_t length;
|
||||
char* 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(json);
|
||||
EXPECT_FALSE(document.HasParseError());
|
||||
|
||||
document.Parse<kParseIterativeFlag>(json);
|
||||
EXPECT_FALSE(document.HasParseError());
|
||||
|
||||
free(json);
|
||||
}
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
static char* ReadFile(const char* filename, size_t& length) {
|
||||
const char *paths[] = {
|
||||
"jsonchecker",
|
||||
"bin/jsonchecker",
|
||||
"../bin/jsonchecker",
|
||||
"../../bin/jsonchecker",
|
||||
"../../../bin/jsonchecker"
|
||||
};
|
||||
char buffer[1024];
|
||||
FILE *fp = 0;
|
||||
for (size_t i = 0; i < sizeof(paths) / sizeof(paths[0]); i++) {
|
||||
sprintf(buffer, "%s/%s", paths[i], filename);
|
||||
fp = fopen(buffer, "rb");
|
||||
if (fp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
length = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* json = static_cast<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];
|
||||
|
||||
// jsonchecker/failXX.json
|
||||
for (int i = 1; i <= 33; i++) {
|
||||
if (i == 1) // fail1.json is valid in rapidjson, which has no limitation on type of root element (RFC 7159).
|
||||
continue;
|
||||
if (i == 18) // fail18.json is valid in rapidjson, which has no limitation on depth of nesting.
|
||||
continue;
|
||||
|
||||
sprintf(filename, "fail%d.json", i);
|
||||
size_t length;
|
||||
char* json = ReadFile(filename, length);
|
||||
if (!json) {
|
||||
printf("jsonchecker file %s not found", filename);
|
||||
ADD_FAILURE();
|
||||
continue;
|
||||
}
|
||||
|
||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||
document.Parse(json);
|
||||
EXPECT_TRUE(document.HasParseError());
|
||||
|
||||
document.Parse<kParseIterativeFlag>(json);
|
||||
EXPECT_TRUE(document.HasParseError());
|
||||
|
||||
free(json);
|
||||
}
|
||||
|
||||
// passX.json
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
sprintf(filename, "pass%d.json", i);
|
||||
size_t length;
|
||||
char* 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(json);
|
||||
EXPECT_FALSE(document.HasParseError());
|
||||
|
||||
document.Parse<kParseIterativeFlag>(json);
|
||||
EXPECT_FALSE(document.HasParseError());
|
||||
|
||||
free(json);
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +1,70 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
// test another instantiation of RapidJSON in a different namespace
|
||||
|
||||
#define RAPIDJSON_NAMESPACE my::rapid::json
|
||||
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapid { namespace json {
|
||||
#define RAPIDJSON_NAMESPACE_END } } }
|
||||
|
||||
// include lots of RapidJSON files
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
static const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}";
|
||||
|
||||
TEST(NamespaceTest,Using) {
|
||||
using namespace RAPIDJSON_NAMESPACE;
|
||||
typedef GenericDocument<UTF8<>, CrtAllocator> DocumentType;
|
||||
DocumentType doc;
|
||||
|
||||
doc.Parse(json);
|
||||
EXPECT_TRUE(!doc.HasParseError());
|
||||
}
|
||||
|
||||
TEST(NamespaceTest,Direct) {
|
||||
typedef RAPIDJSON_NAMESPACE::Document Document;
|
||||
typedef RAPIDJSON_NAMESPACE::Reader Reader;
|
||||
typedef RAPIDJSON_NAMESPACE::StringStream StringStream;
|
||||
typedef RAPIDJSON_NAMESPACE::StringBuffer StringBuffer;
|
||||
typedef RAPIDJSON_NAMESPACE::Writer<StringBuffer> WriterType;
|
||||
|
||||
StringStream s(json);
|
||||
StringBuffer buffer;
|
||||
WriterType writer(buffer);
|
||||
buffer.ShrinkToFit();
|
||||
Reader reader;
|
||||
reader.Parse(s, writer);
|
||||
|
||||
EXPECT_STREQ(json, buffer.GetString());
|
||||
EXPECT_EQ(sizeof(json)-1, buffer.GetSize());
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
|
||||
Document doc;
|
||||
doc.Parse(buffer.GetString());
|
||||
EXPECT_TRUE(!doc.HasParseError());
|
||||
|
||||
buffer.Clear();
|
||||
writer.Reset(buffer);
|
||||
doc.Accept(writer);
|
||||
EXPECT_STREQ(json, buffer.GetString());
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
// test another instantiation of RapidJSON in a different namespace
|
||||
|
||||
#define RAPIDJSON_NAMESPACE my::rapid::json
|
||||
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapid { namespace json {
|
||||
#define RAPIDJSON_NAMESPACE_END } } }
|
||||
|
||||
// include lots of RapidJSON files
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
static const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}";
|
||||
|
||||
TEST(NamespaceTest,Using) {
|
||||
using namespace RAPIDJSON_NAMESPACE;
|
||||
typedef GenericDocument<UTF8<>, CrtAllocator> DocumentType;
|
||||
DocumentType doc;
|
||||
|
||||
doc.Parse(json);
|
||||
EXPECT_TRUE(!doc.HasParseError());
|
||||
}
|
||||
|
||||
TEST(NamespaceTest,Direct) {
|
||||
typedef RAPIDJSON_NAMESPACE::Document Document;
|
||||
typedef RAPIDJSON_NAMESPACE::Reader Reader;
|
||||
typedef RAPIDJSON_NAMESPACE::StringStream StringStream;
|
||||
typedef RAPIDJSON_NAMESPACE::StringBuffer StringBuffer;
|
||||
typedef RAPIDJSON_NAMESPACE::Writer<StringBuffer> WriterType;
|
||||
|
||||
StringStream s(json);
|
||||
StringBuffer buffer;
|
||||
WriterType writer(buffer);
|
||||
buffer.ShrinkToFit();
|
||||
Reader reader;
|
||||
reader.Parse(s, writer);
|
||||
|
||||
EXPECT_STREQ(json, buffer.GetString());
|
||||
EXPECT_EQ(sizeof(json)-1, buffer.GetSize());
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
|
||||
Document doc;
|
||||
doc.Parse(buffer.GetString());
|
||||
EXPECT_TRUE(!doc.HasParseError());
|
||||
|
||||
buffer.Clear();
|
||||
writer.Reset(buffer);
|
||||
doc.Accept(writer);
|
||||
EXPECT_STREQ(json, buffer.GetString());
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
}
|
||||
|
@ -1,50 +1,50 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/rapidjson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic push
|
||||
#if __has_warning("-Wdeprecated")
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
AssertException::~AssertException() throw() {}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
_CrtMemState memoryState = { 0 };
|
||||
_CrtMemCheckpoint(&memoryState);
|
||||
//_CrtSetBreakAlloc(X);
|
||||
//void *testWhetherMemoryLeakDetectionWorks = malloc(1);
|
||||
#endif
|
||||
|
||||
int ret = RUN_ALL_TESTS();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Current gtest constantly leak 2 blocks at exit
|
||||
_CrtMemDumpAllObjectsSince(&memoryState);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
#include "rapidjson/rapidjson.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic push
|
||||
#if __has_warning("-Wdeprecated")
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
AssertException::~AssertException() throw() {}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
std::cout << "RapidJSON v" << RAPIDJSON_VERSION_STRING << std::endl;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
_CrtMemState memoryState = { 0 };
|
||||
_CrtMemCheckpoint(&memoryState);
|
||||
//_CrtSetBreakAlloc(X);
|
||||
//void *testWhetherMemoryLeakDetectionWorks = malloc(1);
|
||||
#endif
|
||||
|
||||
int ret = RUN_ALL_TESTS();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Current gtest constantly leak 2 blocks at exit
|
||||
_CrtMemDumpAllObjectsSince(&memoryState);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,135 +1,135 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef UNITTEST_H_
|
||||
#define UNITTEST_H_
|
||||
|
||||
// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic push
|
||||
#if __has_warning("-Wreserved-id-macro")
|
||||
#pragma GCC diagnostic ignored "-Wreserved-id-macro"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
#pragma warning(disable : 4996) // 'function': was declared deprecated
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
|
||||
#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#endif
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
// All TEST() macro generated this warning, disable globally
|
||||
#pragma GCC diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
|
||||
template <typename Ch>
|
||||
inline unsigned StrLen(const Ch* 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 static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
|
||||
}
|
||||
|
||||
template <typename Ch>
|
||||
inline Ch* StrDup(const Ch* str) {
|
||||
size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1);
|
||||
Ch* buffer = static_cast<Ch*>(malloc(bufferSize));
|
||||
memcpy(buffer, str, bufferSize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline FILE* TempFile(char *filename) {
|
||||
#ifdef _MSC_VER
|
||||
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];
|
||||
|
||||
return fopen(filename, "wb");
|
||||
#else
|
||||
strcpy(filename, "/tmp/fileXXXXXX");
|
||||
int fd = mkstemp(filename);
|
||||
return fdopen(fd, "w");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Use exception for catching assert
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic push
|
||||
#if __has_warning("-Wdeprecated")
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class AssertException : public std::logic_error {
|
||||
public:
|
||||
AssertException(const char* w) : std::logic_error(w) {}
|
||||
AssertException(const AssertException& rhs) : std::logic_error(rhs) {}
|
||||
virtual ~AssertException() throw();
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||
|
||||
class Random {
|
||||
public:
|
||||
Random(unsigned seed = 0) : mSeed(seed) {}
|
||||
|
||||
unsigned operator()() {
|
||||
mSeed = 214013 * mSeed + 2531011;
|
||||
return mSeed;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned mSeed;
|
||||
};
|
||||
|
||||
#endif // UNITTEST_H_
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#ifndef UNITTEST_H_
|
||||
#define UNITTEST_H_
|
||||
|
||||
// gtest indirectly included inttypes.h, without __STDC_CONSTANT_MACROS.
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic push
|
||||
#if __has_warning("-Wreserved-id-macro")
|
||||
#pragma GCC diagnostic ignored "-Wreserved-id-macro"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# define __STDC_CONSTANT_MACROS 1 // required by C++ standard
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <crtdbg.h>
|
||||
#pragma warning(disable : 4996) // 'function': was declared deprecated
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
|
||||
#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic push
|
||||
#endif
|
||||
#pragma GCC diagnostic ignored "-Weffc++"
|
||||
#endif
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
// All TEST() macro generated this warning, disable globally
|
||||
#pragma GCC diagnostic ignored "-Wglobal-constructors"
|
||||
#endif
|
||||
|
||||
template <typename Ch>
|
||||
inline unsigned StrLen(const Ch* 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 static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
|
||||
}
|
||||
|
||||
template <typename Ch>
|
||||
inline Ch* StrDup(const Ch* str) {
|
||||
size_t bufferSize = sizeof(Ch) * (StrLen(str) + 1);
|
||||
Ch* buffer = static_cast<Ch*>(malloc(bufferSize));
|
||||
memcpy(buffer, str, bufferSize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline FILE* TempFile(char *filename) {
|
||||
#ifdef _MSC_VER
|
||||
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];
|
||||
|
||||
return fopen(filename, "wb");
|
||||
#else
|
||||
strcpy(filename, "/tmp/fileXXXXXX");
|
||||
int fd = mkstemp(filename);
|
||||
return fdopen(fd, "w");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Use exception for catching assert
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic push
|
||||
#if __has_warning("-Wdeprecated")
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class AssertException : public std::logic_error {
|
||||
public:
|
||||
AssertException(const char* w) : std::logic_error(w) {}
|
||||
AssertException(const AssertException& rhs) : std::logic_error(rhs) {}
|
||||
virtual ~AssertException() throw();
|
||||
};
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))
|
||||
|
||||
class Random {
|
||||
public:
|
||||
Random(unsigned seed = 0) : mSeed(seed) {}
|
||||
|
||||
unsigned operator()() {
|
||||
mSeed = 214013 * mSeed + 2531011;
|
||||
return mSeed;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned mSeed;
|
||||
};
|
||||
|
||||
#endif // UNITTEST_H_
|
||||
|
@ -1,441 +1,441 @@
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
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);
|
||||
buffer.ShrinkToFit();
|
||||
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<kParseFullPrecisionFlag>(s, writer); \
|
||||
EXPECT_STREQ(json, buffer.GetString()); \
|
||||
EXPECT_TRUE(writer.IsComplete()); \
|
||||
}
|
||||
|
||||
TEST(Writer, Root) {
|
||||
TEST_ROUNDTRIP("null");
|
||||
TEST_ROUNDTRIP("true");
|
||||
TEST_ROUNDTRIP("false");
|
||||
TEST_ROUNDTRIP("0");
|
||||
TEST_ROUNDTRIP("\"foo\"");
|
||||
TEST_ROUNDTRIP("[]");
|
||||
TEST_ROUNDTRIP("{}");
|
||||
}
|
||||
|
||||
TEST(Writer, Int) {
|
||||
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(Writer, Int64) {
|
||||
TEST_ROUNDTRIP("[-1234567890123456789]");
|
||||
TEST_ROUNDTRIP("[-9223372036854775808]");
|
||||
}
|
||||
|
||||
TEST(Writer, Uint64) {
|
||||
TEST_ROUNDTRIP("[1234567890123456789]");
|
||||
TEST_ROUNDTRIP("[9223372036854775807]");
|
||||
}
|
||||
|
||||
TEST(Writer, String) {
|
||||
TEST_ROUNDTRIP("[\"Hello\"]");
|
||||
TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
|
||||
TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.String(std::string("Hello\n"));
|
||||
EXPECT_STREQ("\"Hello\\n\"", buffer.GetString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Writer, Double) {
|
||||
TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]");
|
||||
TEST_ROUNDTRIP("0.0");
|
||||
TEST_ROUNDTRIP("-0.0"); // Issue #289
|
||||
TEST_ROUNDTRIP("1e30");
|
||||
TEST_ROUNDTRIP("1.0");
|
||||
TEST_ROUNDTRIP("5e-324"); // Min subnormal positive double
|
||||
TEST_ROUNDTRIP("2.225073858507201e-308"); // Max subnormal positive double
|
||||
TEST_ROUNDTRIP("2.2250738585072014e-308"); // Min normal positive double
|
||||
TEST_ROUNDTRIP("1.7976931348623157e308"); // Max double
|
||||
|
||||
}
|
||||
|
||||
TEST(Writer, Transcode) {
|
||||
const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}";
|
||||
|
||||
// UTF8 -> UTF16 -> UTF8
|
||||
{
|
||||
StringStream s(json);
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
|
||||
GenericReader<UTF8<>, UTF16<> > reader;
|
||||
reader.Parse(s, writer);
|
||||
EXPECT_STREQ(json, buffer.GetString());
|
||||
}
|
||||
|
||||
// UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8
|
||||
{
|
||||
StringStream s(json);
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF8<>, ASCII<> > writer(buffer);
|
||||
Reader reader;
|
||||
reader.Parse(s, writer);
|
||||
|
||||
StringBuffer buffer2;
|
||||
Writer<StringBuffer> writer2(buffer2);
|
||||
GenericReader<ASCII<>, UTF8<> > reader2;
|
||||
StringStream s2(buffer.GetString());
|
||||
reader2.Parse(s2, writer2);
|
||||
|
||||
EXPECT_STREQ(json, buffer2.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
#include <sstream>
|
||||
|
||||
class OStreamWrapper {
|
||||
public:
|
||||
typedef char Ch;
|
||||
|
||||
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* 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&);
|
||||
|
||||
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], \"u64\": 1234567890123456789, \"i64\":-1234567890123456789 } ");
|
||||
|
||||
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],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}", actual.c_str());
|
||||
}
|
||||
|
||||
TEST(Writer, AssertRootMayBeAnyValue) {
|
||||
#define T(x)\
|
||||
{\
|
||||
StringBuffer buffer;\
|
||||
Writer<StringBuffer> writer(buffer);\
|
||||
EXPECT_TRUE(x);\
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(Writer, AssertIncorrectArrayLevel) {
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(Writer, AssertIncorrectEndArray) {
|
||||
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());
|
||||
#undef T
|
||||
}
|
||||
|
||||
TEST(Writer, AssertMultipleRoot) {
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
|
||||
writer.StartObject();
|
||||
writer.EndObject();
|
||||
ASSERT_THROW(writer.StartObject(), AssertException);
|
||||
|
||||
writer.Reset(buffer);
|
||||
writer.Null();
|
||||
ASSERT_THROW(writer.Int(0), AssertException);
|
||||
|
||||
writer.Reset(buffer);
|
||||
writer.String("foo");
|
||||
ASSERT_THROW(writer.StartArray(), AssertException);
|
||||
|
||||
writer.Reset(buffer);
|
||||
writer.StartArray();
|
||||
writer.EndArray();
|
||||
//ASSERT_THROW(writer.Double(3.14), 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());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
TEST(Writer, RootValueIsComplete) {
|
||||
#define T(x)\
|
||||
{\
|
||||
StringBuffer buffer;\
|
||||
Writer<StringBuffer> writer(buffer);\
|
||||
EXPECT_FALSE(writer.IsComplete()); \
|
||||
x; \
|
||||
EXPECT_TRUE(writer.IsComplete()); \
|
||||
}
|
||||
T(writer.Null());
|
||||
T(writer.Bool(true));
|
||||
T(writer.Bool(false));
|
||||
T(writer.Int(0));
|
||||
T(writer.Uint(0));
|
||||
T(writer.Int64(0));
|
||||
T(writer.Uint64(0));
|
||||
T(writer.Double(0));
|
||||
T(writer.String(""));
|
||||
#undef T
|
||||
}
|
||||
|
||||
TEST(Writer, InvalidEncoding) {
|
||||
// Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
{
|
||||
GenericStringBuffer<UTF16<> > buffer;
|
||||
Writer<GenericStringBuffer<UTF16<> >, UTF8<>, UTF16<> > writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_FALSE(writer.String("\xfe"));
|
||||
EXPECT_FALSE(writer.String("\xff"));
|
||||
EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff"));
|
||||
writer.EndArray();
|
||||
}
|
||||
|
||||
// Fail in encoding
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF32<> > writer(buffer);
|
||||
static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
|
||||
EXPECT_FALSE(writer.String(s));
|
||||
}
|
||||
|
||||
// Fail in unicode escaping in ASCII output
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF32<>, ASCII<> > writer(buffer);
|
||||
static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
|
||||
EXPECT_FALSE(writer.String(s));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Writer, ValidateEncoding) {
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_TRUE(writer.String("\x24")); // Dollar sign U+0024
|
||||
EXPECT_TRUE(writer.String("\xC2\xA2")); // Cents sign U+00A2
|
||||
EXPECT_TRUE(writer.String("\xE2\x82\xAC")); // Euro sign U+20AC
|
||||
EXPECT_TRUE(writer.String("\xF0\x9D\x84\x9E")); // G clef sign U+1D11E
|
||||
writer.EndArray();
|
||||
EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\"]", buffer.GetString());
|
||||
}
|
||||
|
||||
// Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_FALSE(writer.String("\xfe"));
|
||||
EXPECT_FALSE(writer.String("\xff"));
|
||||
EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff"));
|
||||
writer.EndArray();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Writer, InvalidEventSequence) {
|
||||
// {]
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
EXPECT_THROW(writer.EndArray(), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
|
||||
// [}
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_THROW(writer.EndObject(), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
|
||||
// { 1:
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
EXPECT_THROW(writer.Int(1), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
}
|
||||
|
||||
extern double zero; // clang -Wmissing-variable-declarations
|
||||
double zero = 0.0; // Use global variable to prevent compiler warning
|
||||
|
||||
TEST(Writer, NaN) {
|
||||
double nan = zero / zero;
|
||||
EXPECT_TRUE(internal::Double(nan).IsNan());
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(nan));
|
||||
}
|
||||
|
||||
TEST(Writer, Inf) {
|
||||
double inf = 1.0 / zero;
|
||||
EXPECT_TRUE(internal::Double(inf).IsInf());
|
||||
StringBuffer buffer;
|
||||
{
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(inf));
|
||||
}
|
||||
{
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(-inf));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Writer, RawValue) {
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
writer.Key("a");
|
||||
writer.Int(1);
|
||||
writer.Key("raw");
|
||||
const char json[] = "[\"Hello\\nWorld\", 123.456]";
|
||||
writer.RawValue(json, strlen(json), kArrayType);
|
||||
writer.EndObject();
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString());
|
||||
}
|
||||
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||
//
|
||||
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||
//
|
||||
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||
// in compliance with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
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);
|
||||
buffer.ShrinkToFit();
|
||||
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<kParseFullPrecisionFlag>(s, writer); \
|
||||
EXPECT_STREQ(json, buffer.GetString()); \
|
||||
EXPECT_TRUE(writer.IsComplete()); \
|
||||
}
|
||||
|
||||
TEST(Writer, Root) {
|
||||
TEST_ROUNDTRIP("null");
|
||||
TEST_ROUNDTRIP("true");
|
||||
TEST_ROUNDTRIP("false");
|
||||
TEST_ROUNDTRIP("0");
|
||||
TEST_ROUNDTRIP("\"foo\"");
|
||||
TEST_ROUNDTRIP("[]");
|
||||
TEST_ROUNDTRIP("{}");
|
||||
}
|
||||
|
||||
TEST(Writer, Int) {
|
||||
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(Writer, Int64) {
|
||||
TEST_ROUNDTRIP("[-1234567890123456789]");
|
||||
TEST_ROUNDTRIP("[-9223372036854775808]");
|
||||
}
|
||||
|
||||
TEST(Writer, Uint64) {
|
||||
TEST_ROUNDTRIP("[1234567890123456789]");
|
||||
TEST_ROUNDTRIP("[9223372036854775807]");
|
||||
}
|
||||
|
||||
TEST(Writer, String) {
|
||||
TEST_ROUNDTRIP("[\"Hello\"]");
|
||||
TEST_ROUNDTRIP("[\"Hello\\u0000World\"]");
|
||||
TEST_ROUNDTRIP("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]");
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.String(std::string("Hello\n"));
|
||||
EXPECT_STREQ("\"Hello\\n\"", buffer.GetString());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Writer, Double) {
|
||||
TEST_ROUNDTRIP("[1.2345,1.2345678,0.123456789012,1234567.8]");
|
||||
TEST_ROUNDTRIP("0.0");
|
||||
TEST_ROUNDTRIP("-0.0"); // Issue #289
|
||||
TEST_ROUNDTRIP("1e30");
|
||||
TEST_ROUNDTRIP("1.0");
|
||||
TEST_ROUNDTRIP("5e-324"); // Min subnormal positive double
|
||||
TEST_ROUNDTRIP("2.225073858507201e-308"); // Max subnormal positive double
|
||||
TEST_ROUNDTRIP("2.2250738585072014e-308"); // Min normal positive double
|
||||
TEST_ROUNDTRIP("1.7976931348623157e308"); // Max double
|
||||
|
||||
}
|
||||
|
||||
TEST(Writer, Transcode) {
|
||||
const char json[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3],\"dollar\":\"\x24\",\"cents\":\"\xC2\xA2\",\"euro\":\"\xE2\x82\xAC\",\"gclef\":\"\xF0\x9D\x84\x9E\"}";
|
||||
|
||||
// UTF8 -> UTF16 -> UTF8
|
||||
{
|
||||
StringStream s(json);
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF16<>, UTF8<> > writer(buffer);
|
||||
GenericReader<UTF8<>, UTF16<> > reader;
|
||||
reader.Parse(s, writer);
|
||||
EXPECT_STREQ(json, buffer.GetString());
|
||||
}
|
||||
|
||||
// UTF8 -> UTF8 -> ASCII -> UTF8 -> UTF8
|
||||
{
|
||||
StringStream s(json);
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF8<>, ASCII<> > writer(buffer);
|
||||
Reader reader;
|
||||
reader.Parse(s, writer);
|
||||
|
||||
StringBuffer buffer2;
|
||||
Writer<StringBuffer> writer2(buffer2);
|
||||
GenericReader<ASCII<>, UTF8<> > reader2;
|
||||
StringStream s2(buffer.GetString());
|
||||
reader2.Parse(s2, writer2);
|
||||
|
||||
EXPECT_STREQ(json, buffer2.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
#include <sstream>
|
||||
|
||||
class OStreamWrapper {
|
||||
public:
|
||||
typedef char Ch;
|
||||
|
||||
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* 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&);
|
||||
|
||||
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], \"u64\": 1234567890123456789, \"i64\":-1234567890123456789 } ");
|
||||
|
||||
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],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}", actual.c_str());
|
||||
}
|
||||
|
||||
TEST(Writer, AssertRootMayBeAnyValue) {
|
||||
#define T(x)\
|
||||
{\
|
||||
StringBuffer buffer;\
|
||||
Writer<StringBuffer> writer(buffer);\
|
||||
EXPECT_TRUE(x);\
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(Writer, AssertIncorrectArrayLevel) {
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(Writer, AssertIncorrectEndArray) {
|
||||
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());
|
||||
#undef T
|
||||
}
|
||||
|
||||
TEST(Writer, AssertMultipleRoot) {
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
|
||||
writer.StartObject();
|
||||
writer.EndObject();
|
||||
ASSERT_THROW(writer.StartObject(), AssertException);
|
||||
|
||||
writer.Reset(buffer);
|
||||
writer.Null();
|
||||
ASSERT_THROW(writer.Int(0), AssertException);
|
||||
|
||||
writer.Reset(buffer);
|
||||
writer.String("foo");
|
||||
ASSERT_THROW(writer.StartArray(), AssertException);
|
||||
|
||||
writer.Reset(buffer);
|
||||
writer.StartArray();
|
||||
writer.EndArray();
|
||||
//ASSERT_THROW(writer.Double(3.14), 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());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
TEST(Writer, RootValueIsComplete) {
|
||||
#define T(x)\
|
||||
{\
|
||||
StringBuffer buffer;\
|
||||
Writer<StringBuffer> writer(buffer);\
|
||||
EXPECT_FALSE(writer.IsComplete()); \
|
||||
x; \
|
||||
EXPECT_TRUE(writer.IsComplete()); \
|
||||
}
|
||||
T(writer.Null());
|
||||
T(writer.Bool(true));
|
||||
T(writer.Bool(false));
|
||||
T(writer.Int(0));
|
||||
T(writer.Uint(0));
|
||||
T(writer.Int64(0));
|
||||
T(writer.Uint64(0));
|
||||
T(writer.Double(0));
|
||||
T(writer.String(""));
|
||||
#undef T
|
||||
}
|
||||
|
||||
TEST(Writer, InvalidEncoding) {
|
||||
// Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
{
|
||||
GenericStringBuffer<UTF16<> > buffer;
|
||||
Writer<GenericStringBuffer<UTF16<> >, UTF8<>, UTF16<> > writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_FALSE(writer.String("\xfe"));
|
||||
EXPECT_FALSE(writer.String("\xff"));
|
||||
EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff"));
|
||||
writer.EndArray();
|
||||
}
|
||||
|
||||
// Fail in encoding
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF32<> > writer(buffer);
|
||||
static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
|
||||
EXPECT_FALSE(writer.String(s));
|
||||
}
|
||||
|
||||
// Fail in unicode escaping in ASCII output
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF32<>, ASCII<> > writer(buffer);
|
||||
static const UTF32<>::Ch s[] = { 0x110000, 0 }; // Out of U+0000 to U+10FFFF
|
||||
EXPECT_FALSE(writer.String(s));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Writer, ValidateEncoding) {
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_TRUE(writer.String("\x24")); // Dollar sign U+0024
|
||||
EXPECT_TRUE(writer.String("\xC2\xA2")); // Cents sign U+00A2
|
||||
EXPECT_TRUE(writer.String("\xE2\x82\xAC")); // Euro sign U+20AC
|
||||
EXPECT_TRUE(writer.String("\xF0\x9D\x84\x9E")); // G clef sign U+1D11E
|
||||
writer.EndArray();
|
||||
EXPECT_STREQ("[\"\x24\",\"\xC2\xA2\",\"\xE2\x82\xAC\",\"\xF0\x9D\x84\x9E\"]", buffer.GetString());
|
||||
}
|
||||
|
||||
// Fail in decoding invalid UTF-8 sequence http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteValidateEncodingFlag> writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_FALSE(writer.String("\xfe"));
|
||||
EXPECT_FALSE(writer.String("\xff"));
|
||||
EXPECT_FALSE(writer.String("\xfe\xfe\xff\xff"));
|
||||
writer.EndArray();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Writer, InvalidEventSequence) {
|
||||
// {]
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
EXPECT_THROW(writer.EndArray(), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
|
||||
// [}
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartArray();
|
||||
EXPECT_THROW(writer.EndObject(), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
|
||||
// { 1:
|
||||
{
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
EXPECT_THROW(writer.Int(1), AssertException);
|
||||
EXPECT_FALSE(writer.IsComplete());
|
||||
}
|
||||
}
|
||||
|
||||
extern double zero; // clang -Wmissing-variable-declarations
|
||||
double zero = 0.0; // Use global variable to prevent compiler warning
|
||||
|
||||
TEST(Writer, NaN) {
|
||||
double nan = zero / zero;
|
||||
EXPECT_TRUE(internal::Double(nan).IsNan());
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(nan));
|
||||
}
|
||||
|
||||
TEST(Writer, Inf) {
|
||||
double inf = 1.0 / zero;
|
||||
EXPECT_TRUE(internal::Double(inf).IsInf());
|
||||
StringBuffer buffer;
|
||||
{
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(inf));
|
||||
}
|
||||
{
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(-inf));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Writer, RawValue) {
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
writer.StartObject();
|
||||
writer.Key("a");
|
||||
writer.Int(1);
|
||||
writer.Key("raw");
|
||||
const char json[] = "[\"Hello\\nWorld\", 123.456]";
|
||||
writer.RawValue(json, strlen(json), kArrayType);
|
||||
writer.EndObject();
|
||||
EXPECT_TRUE(writer.IsComplete());
|
||||
EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user