mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-23 16:09:47 +00:00
(rapidjson) Remove unused files
This commit is contained in:
parent
9aa008834e
commit
a117811936
@ -1,42 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
if(POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
|
||||
set(EXAMPLES
|
||||
capitalize
|
||||
condense
|
||||
filterkey
|
||||
filterkeydom
|
||||
jsonx
|
||||
messagereader
|
||||
parsebyparts
|
||||
pretty
|
||||
prettyauto
|
||||
schemavalidator
|
||||
serialize
|
||||
simpledom
|
||||
simplereader
|
||||
simplewriter
|
||||
tutorial)
|
||||
|
||||
include_directories("../include/")
|
||||
|
||||
add_definitions(-D__STDC_FORMAT_MACROS)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
|
||||
endif()
|
||||
|
||||
foreach (example ${EXAMPLES})
|
||||
add_executable(${example} ${example}/${example}.cpp)
|
||||
endforeach()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
target_link_libraries(parsebyparts pthread)
|
||||
endif()
|
||||
|
||||
add_custom_target(examples ALL DEPENDS ${EXAMPLES})
|
@ -1,67 +0,0 @@
|
||||
// JSON condenser example
|
||||
|
||||
// This example parses JSON from stdin with validation,
|
||||
// and re-output the JSON content to stdout with all string capitalized, and without whitespace.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
#include <vector>
|
||||
#include <cctype>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template<typename OutputHandler>
|
||||
struct CapitalizeFilter {
|
||||
CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {}
|
||||
|
||||
bool Null() { return out_.Null(); }
|
||||
bool Bool(bool b) { return out_.Bool(b); }
|
||||
bool Int(int i) { return out_.Int(i); }
|
||||
bool Uint(unsigned u) { return out_.Uint(u); }
|
||||
bool Int64(int64_t i) { return out_.Int64(i); }
|
||||
bool Uint64(uint64_t u) { return out_.Uint64(u); }
|
||||
bool Double(double d) { return out_.Double(d); }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) { return out_.RawNumber(str, length, copy); }
|
||||
bool String(const char* str, SizeType length, bool) {
|
||||
buffer_.clear();
|
||||
for (SizeType i = 0; i < length; i++)
|
||||
buffer_.push_back(static_cast<char>(std::toupper(str[i])));
|
||||
return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
|
||||
}
|
||||
bool StartObject() { return out_.StartObject(); }
|
||||
bool Key(const char* str, SizeType length, bool copy) { return String(str, length, copy); }
|
||||
bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); }
|
||||
bool StartArray() { return out_.StartArray(); }
|
||||
bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
|
||||
|
||||
OutputHandler& out_;
|
||||
std::vector<char> buffer_;
|
||||
|
||||
private:
|
||||
CapitalizeFilter(const CapitalizeFilter&);
|
||||
CapitalizeFilter& operator=(const CapitalizeFilter&);
|
||||
};
|
||||
|
||||
int main(int, char*[]) {
|
||||
// Prepare JSON reader and input stream.
|
||||
Reader reader;
|
||||
char readBuffer[65536];
|
||||
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
|
||||
|
||||
// Prepare JSON writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
|
||||
Writer<FileWriteStream> writer(os);
|
||||
|
||||
// JSON reader parse from the input stream and let writer generate the output.
|
||||
CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
|
||||
if (!reader.Parse(is, filter)) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,32 +0,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,135 +0,0 @@
|
||||
// JSON filterkey example with SAX-style API.
|
||||
|
||||
// This example parses JSON text from stdin with validation.
|
||||
// During parsing, specified key will be filtered using a SAX handler.
|
||||
// It 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"
|
||||
#include <stack>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
// This handler forwards event into an output handler, with filtering the descendent events of specified key.
|
||||
template <typename OutputHandler>
|
||||
class FilterKeyHandler {
|
||||
public:
|
||||
typedef char Ch;
|
||||
|
||||
FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, SizeType keyLength) :
|
||||
outputHandler_(outputHandler), keyString_(keyString), keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_()
|
||||
{}
|
||||
|
||||
bool Null() { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Null() && EndValue(); }
|
||||
bool Bool(bool b) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Bool(b) && EndValue(); }
|
||||
bool Int(int i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int(i) && EndValue(); }
|
||||
bool Uint(unsigned u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint(u) && EndValue(); }
|
||||
bool Int64(int64_t i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int64(i) && EndValue(); }
|
||||
bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint64(u) && EndValue(); }
|
||||
bool Double(double d) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Double(d) && EndValue(); }
|
||||
bool RawNumber(const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) && EndValue(); }
|
||||
bool String (const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.String (str, len, copy) && EndValue(); }
|
||||
|
||||
bool StartObject() {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_++;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
filteredKeyCount_.push(0);
|
||||
return outputHandler_.StartObject();
|
||||
}
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType len, bool copy) {
|
||||
if (filterValueDepth_ > 0)
|
||||
return true;
|
||||
else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) {
|
||||
filterValueDepth_ = 1;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
++filteredKeyCount_.top();
|
||||
return outputHandler_.Key(str, len, copy);
|
||||
}
|
||||
}
|
||||
|
||||
bool EndObject(SizeType) {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_--;
|
||||
return EndValue();
|
||||
}
|
||||
else {
|
||||
// Use our own filtered memberCount
|
||||
SizeType memberCount = filteredKeyCount_.top();
|
||||
filteredKeyCount_.pop();
|
||||
return outputHandler_.EndObject(memberCount) && EndValue();
|
||||
}
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return outputHandler_.StartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType elementCount) {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_--;
|
||||
return EndValue();
|
||||
}
|
||||
else
|
||||
return outputHandler_.EndArray(elementCount) && EndValue();
|
||||
}
|
||||
|
||||
private:
|
||||
FilterKeyHandler(const FilterKeyHandler&);
|
||||
FilterKeyHandler& operator=(const FilterKeyHandler&);
|
||||
|
||||
bool EndValue() {
|
||||
if (filterValueDepth_ == 1) // Just at the end of value after filtered key
|
||||
filterValueDepth_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputHandler& outputHandler_;
|
||||
const char* keyString_;
|
||||
const SizeType keyLength_;
|
||||
unsigned filterValueDepth_;
|
||||
std::stack<SizeType> filteredKeyCount_;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "filterkey key < input.json > output.json\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare JSON reader and input stream.
|
||||
Reader reader;
|
||||
char readBuffer[65536];
|
||||
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
|
||||
|
||||
// Prepare JSON writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
|
||||
Writer<FileWriteStream> writer(os);
|
||||
|
||||
// Prepare Filter
|
||||
FilterKeyHandler<Writer<FileWriteStream> > filter(writer, argv[1], static_cast<SizeType>(strlen(argv[1])));
|
||||
|
||||
// JSON reader parse from the input stream, filter handler filters the events, and forward to writer.
|
||||
// i.e. the events flow is: reader -> filter -> writer
|
||||
if (!reader.Parse(is, filter)) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
// JSON filterkey example which populates filtered SAX events into a Document.
|
||||
|
||||
// This example parses JSON text from stdin with validation.
|
||||
// During parsing, specified key will be filtered using a SAX handler.
|
||||
// And finally the filtered events are used to populate a Document.
|
||||
// As an example, the document is written to standard output.
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
#include <stack>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
// This handler forwards event into an output handler, with filtering the descendent events of specified key.
|
||||
template <typename OutputHandler>
|
||||
class FilterKeyHandler {
|
||||
public:
|
||||
typedef char Ch;
|
||||
|
||||
FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, SizeType keyLength) :
|
||||
outputHandler_(outputHandler), keyString_(keyString), keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_()
|
||||
{}
|
||||
|
||||
bool Null() { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Null() && EndValue(); }
|
||||
bool Bool(bool b) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Bool(b) && EndValue(); }
|
||||
bool Int(int i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int(i) && EndValue(); }
|
||||
bool Uint(unsigned u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint(u) && EndValue(); }
|
||||
bool Int64(int64_t i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int64(i) && EndValue(); }
|
||||
bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint64(u) && EndValue(); }
|
||||
bool Double(double d) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Double(d) && EndValue(); }
|
||||
bool RawNumber(const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) && EndValue(); }
|
||||
bool String (const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.String (str, len, copy) && EndValue(); }
|
||||
|
||||
bool StartObject() {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_++;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
filteredKeyCount_.push(0);
|
||||
return outputHandler_.StartObject();
|
||||
}
|
||||
}
|
||||
|
||||
bool Key(const Ch* str, SizeType len, bool copy) {
|
||||
if (filterValueDepth_ > 0)
|
||||
return true;
|
||||
else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) {
|
||||
filterValueDepth_ = 1;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
++filteredKeyCount_.top();
|
||||
return outputHandler_.Key(str, len, copy);
|
||||
}
|
||||
}
|
||||
|
||||
bool EndObject(SizeType) {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_--;
|
||||
return EndValue();
|
||||
}
|
||||
else {
|
||||
// Use our own filtered memberCount
|
||||
SizeType memberCount = filteredKeyCount_.top();
|
||||
filteredKeyCount_.pop();
|
||||
return outputHandler_.EndObject(memberCount) && EndValue();
|
||||
}
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return outputHandler_.StartArray();
|
||||
}
|
||||
|
||||
bool EndArray(SizeType elementCount) {
|
||||
if (filterValueDepth_ > 0) {
|
||||
filterValueDepth_--;
|
||||
return EndValue();
|
||||
}
|
||||
else
|
||||
return outputHandler_.EndArray(elementCount) && EndValue();
|
||||
}
|
||||
|
||||
private:
|
||||
FilterKeyHandler(const FilterKeyHandler&);
|
||||
FilterKeyHandler& operator=(const FilterKeyHandler&);
|
||||
|
||||
bool EndValue() {
|
||||
if (filterValueDepth_ == 1) // Just at the end of value after filtered key
|
||||
filterValueDepth_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
OutputHandler& outputHandler_;
|
||||
const char* keyString_;
|
||||
const SizeType keyLength_;
|
||||
unsigned filterValueDepth_;
|
||||
std::stack<SizeType> filteredKeyCount_;
|
||||
};
|
||||
|
||||
// Implements a generator for Document::Populate()
|
||||
template <typename InputStream>
|
||||
class FilterKeyReader {
|
||||
public:
|
||||
typedef char Ch;
|
||||
|
||||
FilterKeyReader(InputStream& is, const Ch* keyString, SizeType keyLength) :
|
||||
is_(is), keyString_(keyString), keyLength_(keyLength), parseResult_()
|
||||
{}
|
||||
|
||||
// SAX event flow: reader -> filter -> handler
|
||||
template <typename Handler>
|
||||
bool operator()(Handler& handler) {
|
||||
FilterKeyHandler<Handler> filter(handler, keyString_, keyLength_);
|
||||
Reader reader;
|
||||
parseResult_ = reader.Parse(is_, filter);
|
||||
return parseResult_;
|
||||
}
|
||||
|
||||
const ParseResult& GetParseResult() const { return parseResult_; }
|
||||
|
||||
private:
|
||||
FilterKeyReader(const FilterKeyReader&);
|
||||
FilterKeyReader& operator=(const FilterKeyReader&);
|
||||
|
||||
InputStream& is_;
|
||||
const char* keyString_;
|
||||
const SizeType keyLength_;
|
||||
ParseResult parseResult_;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "filterkeydom key < input.json > output.json\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare input stream.
|
||||
char readBuffer[65536];
|
||||
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
|
||||
|
||||
// Prepare Filter
|
||||
FilterKeyReader<FileReadStream> reader(is, argv[1], static_cast<SizeType>(strlen(argv[1])));
|
||||
|
||||
// Populates the filtered events from reader
|
||||
Document document;
|
||||
document.Populate(reader);
|
||||
ParseResult pr = reader.GetParseResult();
|
||||
if (!pr) {
|
||||
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(pr.Offset()), GetParseError_En(pr.Code()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare JSON writer and output stream.
|
||||
char writeBuffer[65536];
|
||||
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
|
||||
Writer<FileWriteStream> writer(os);
|
||||
|
||||
// Write the document to standard output
|
||||
document.Accept(writer);
|
||||
return 0;
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
// JSON to JSONx conversion exmaple, using SAX API.
|
||||
// JSONx is an IBM standard format to represent JSON as XML.
|
||||
// https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html
|
||||
// This example parses JSON text from stdin with validation,
|
||||
// and convert to JSONx format to stdout.
|
||||
// Need compile with -D__STDC_FORMAT_MACROS for defining PRId64 and PRIu64 macros.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
#include <cstdio>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
// For simplicity, this example only read/write in UTF-8 encoding
|
||||
template <typename OutputStream>
|
||||
class JsonxWriter {
|
||||
public:
|
||||
JsonxWriter(OutputStream& os) : os_(os), name_(), level_(0), hasName_(false) {
|
||||
}
|
||||
|
||||
bool Null() {
|
||||
return WriteStartElement("null", true);
|
||||
}
|
||||
|
||||
bool Bool(bool b) {
|
||||
return
|
||||
WriteStartElement("boolean") &&
|
||||
WriteString(b ? "true" : "false") &&
|
||||
WriteEndElement("boolean");
|
||||
}
|
||||
|
||||
bool Int(int i) {
|
||||
char buffer[12];
|
||||
return WriteNumberElement(buffer, sprintf(buffer, "%d", i));
|
||||
}
|
||||
|
||||
bool Uint(unsigned i) {
|
||||
char buffer[11];
|
||||
return WriteNumberElement(buffer, sprintf(buffer, "%u", i));
|
||||
}
|
||||
|
||||
bool Int64(int64_t i) {
|
||||
char buffer[21];
|
||||
return WriteNumberElement(buffer, sprintf(buffer, "%" PRId64, i));
|
||||
}
|
||||
|
||||
bool Uint64(uint64_t i) {
|
||||
char buffer[21];
|
||||
return WriteNumberElement(buffer, sprintf(buffer, "%" PRIu64, i));
|
||||
}
|
||||
|
||||
bool Double(double d) {
|
||||
char buffer[30];
|
||||
return WriteNumberElement(buffer, sprintf(buffer, "%.17g", d));
|
||||
}
|
||||
|
||||
bool RawNumber(const char* str, SizeType length, bool) {
|
||||
return
|
||||
WriteStartElement("number") &&
|
||||
WriteEscapedText(str, length) &&
|
||||
WriteEndElement("number");
|
||||
}
|
||||
|
||||
bool String(const char* str, SizeType length, bool) {
|
||||
return
|
||||
WriteStartElement("string") &&
|
||||
WriteEscapedText(str, length) &&
|
||||
WriteEndElement("string");
|
||||
}
|
||||
|
||||
bool StartObject() {
|
||||
return WriteStartElement("object");
|
||||
}
|
||||
|
||||
bool Key(const char* str, SizeType length, bool) {
|
||||
// backup key to name_
|
||||
name_.Clear();
|
||||
for (SizeType i = 0; i < length; i++)
|
||||
name_.Put(str[i]);
|
||||
hasName_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EndObject(SizeType) {
|
||||
return WriteEndElement("object");
|
||||
}
|
||||
|
||||
bool StartArray() {
|
||||
return WriteStartElement("array");
|
||||
}
|
||||
|
||||
bool EndArray(SizeType) {
|
||||
return WriteEndElement("array");
|
||||
}
|
||||
|
||||
private:
|
||||
bool WriteString(const char* s) {
|
||||
while (*s)
|
||||
os_.Put(*s++);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEscapedAttributeValue(const char* s, size_t length) {
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
switch (s[i]) {
|
||||
case '&': WriteString("&"); break;
|
||||
case '<': WriteString("<"); break;
|
||||
case '"': WriteString("""); break;
|
||||
default: os_.Put(s[i]); break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteEscapedText(const char* s, size_t length) {
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
switch (s[i]) {
|
||||
case '&': WriteString("&"); break;
|
||||
case '<': WriteString("<"); break;
|
||||
default: os_.Put(s[i]); break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteStartElement(const char* type, bool emptyElement = false) {
|
||||
if (level_ == 0)
|
||||
if (!WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))
|
||||
return false;
|
||||
|
||||
if (!WriteString("<json:") || !WriteString(type))
|
||||
return false;
|
||||
|
||||
// For root element, need to add declarations
|
||||
if (level_ == 0) {
|
||||
if (!WriteString(
|
||||
" xsi:schemaLocation=\"http://www.datapower.com/schemas/json jsonx.xsd\""
|
||||
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
|
||||
" xmlns:json=\"http://www.ibm.com/xmlns/prod/2009/jsonx\""))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasName_) {
|
||||
hasName_ = false;
|
||||
if (!WriteString(" name=\"") ||
|
||||
!WriteEscapedAttributeValue(name_.GetString(), name_.GetSize()) ||
|
||||
!WriteString("\""))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (emptyElement)
|
||||
return WriteString("/>");
|
||||
else {
|
||||
level_++;
|
||||
return WriteString(">");
|
||||
}
|
||||
}
|
||||
|
||||
bool WriteEndElement(const char* type) {
|
||||
if (!WriteString("</json:") ||
|
||||
!WriteString(type) ||
|
||||
!WriteString(">"))
|
||||
return false;
|
||||
|
||||
// For the last end tag, flush the output stream.
|
||||
if (--level_ == 0)
|
||||
os_.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteNumberElement(const char* buffer, int length) {
|
||||
if (!WriteStartElement("number"))
|
||||
return false;
|
||||
for (int j = 0; j < length; j++)
|
||||
os_.Put(buffer[j]);
|
||||
return WriteEndElement("number");
|
||||
}
|
||||
|
||||
OutputStream& os_;
|
||||
StringBuffer name_;
|
||||
unsigned level_;
|
||||
bool hasName_;
|
||||
};
|
||||
|
||||
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));
|
||||
JsonxWriter<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,105 +0,0 @@
|
||||
// Reading a message JSON with Reader (SAX-style API).
|
||||
// The JSON should be an object with key-string pairs.
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
using namespace rapidjson;
|
||||
|
||||
typedef map<string, string> MessageMap;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||
#endif
|
||||
|
||||
struct MessageHandler
|
||||
: public BaseReaderHandler<UTF8<>, MessageHandler> {
|
||||
MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
|
||||
|
||||
bool StartObject() {
|
||||
switch (state_) {
|
||||
case kExpectObjectStart:
|
||||
state_ = kExpectNameOrObjectEnd;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool String(const char* str, SizeType length, bool) {
|
||||
switch (state_) {
|
||||
case kExpectNameOrObjectEnd:
|
||||
name_ = string(str, length);
|
||||
state_ = kExpectValue;
|
||||
return true;
|
||||
case kExpectValue:
|
||||
messages_.insert(MessageMap::value_type(name_, string(str, length)));
|
||||
state_ = kExpectNameOrObjectEnd;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
|
||||
|
||||
bool Default() { return false; } // All other events are invalid.
|
||||
|
||||
MessageMap messages_;
|
||||
enum State {
|
||||
kExpectObjectStart,
|
||||
kExpectNameOrObjectEnd,
|
||||
kExpectValue
|
||||
}state_;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
#if defined(__GNUC__)
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
||||
|
||||
static void ParseMessages(const char* json, MessageMap& messages) {
|
||||
Reader reader;
|
||||
MessageHandler handler;
|
||||
StringStream ss(json);
|
||||
if (reader.Parse(ss, handler))
|
||||
messages.swap(handler.messages_); // Only change it if success.
|
||||
else {
|
||||
ParseErrorCode e = reader.GetParseErrorCode();
|
||||
size_t o = reader.GetErrorOffset();
|
||||
cout << "Error: " << GetParseError_En(e) << endl;;
|
||||
cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
MessageMap messages;
|
||||
|
||||
const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }";
|
||||
cout << json1 << endl;
|
||||
ParseMessages(json1, messages);
|
||||
|
||||
for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)
|
||||
cout << itr->first << ": " << itr->second << endl;
|
||||
|
||||
cout << endl << "Parse a JSON with invalid schema." << endl;
|
||||
const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }";
|
||||
cout << json2 << endl;
|
||||
ParseMessages(json2, messages);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,173 +0,0 @@
|
||||
// Example of parsing JSON to document by parts.
|
||||
|
||||
// Using C++11 threads
|
||||
// Temporarily disable for clang (older version) due to incompatibility with libstdc++
|
||||
#if (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700)) && !defined(__clang__)
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/error/en.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/ostreamwrapper.h"
|
||||
#include <condition_variable>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template<unsigned parseFlags = kParseDefaultFlags>
|
||||
class AsyncDocumentParser {
|
||||
public:
|
||||
AsyncDocumentParser(Document& d)
|
||||
: stream_(*this)
|
||||
, d_(d)
|
||||
, parseThread_(&AsyncDocumentParser::Parse, this)
|
||||
, mutex_()
|
||||
, notEmpty_()
|
||||
, finish_()
|
||||
, completed_()
|
||||
{}
|
||||
|
||||
~AsyncDocumentParser() {
|
||||
if (!parseThread_.joinable())
|
||||
return;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
|
||||
// Wait until the buffer is read up (or parsing is completed)
|
||||
while (!stream_.Empty() && !completed_)
|
||||
finish_.wait(lock);
|
||||
|
||||
// Automatically append '\0' as the terminator in the stream.
|
||||
static const char terminator[] = "";
|
||||
stream_.src_ = terminator;
|
||||
stream_.end_ = terminator + 1;
|
||||
notEmpty_.notify_one(); // unblock the AsyncStringStream
|
||||
}
|
||||
|
||||
parseThread_.join();
|
||||
}
|
||||
|
||||
void ParsePart(const char* buffer, size_t length) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
|
||||
// Wait until the buffer is read up (or parsing is completed)
|
||||
while (!stream_.Empty() && !completed_)
|
||||
finish_.wait(lock);
|
||||
|
||||
// Stop further parsing if the parsing process is completed.
|
||||
if (completed_)
|
||||
return;
|
||||
|
||||
// Set the buffer to stream and unblock the AsyncStringStream
|
||||
stream_.src_ = buffer;
|
||||
stream_.end_ = buffer + length;
|
||||
notEmpty_.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
void Parse() {
|
||||
d_.ParseStream<parseFlags>(stream_);
|
||||
|
||||
// The stream may not be fully read, notify finish anyway to unblock ParsePart()
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
completed_ = true; // Parsing process is completed
|
||||
finish_.notify_one(); // Unblock ParsePart() or destructor if they are waiting.
|
||||
}
|
||||
|
||||
struct AsyncStringStream {
|
||||
typedef char Ch;
|
||||
|
||||
AsyncStringStream(AsyncDocumentParser& parser) : parser_(parser), src_(), end_(), count_() {}
|
||||
|
||||
char Peek() const {
|
||||
std::unique_lock<std::mutex> lock(parser_.mutex_);
|
||||
|
||||
// If nothing in stream, block to wait.
|
||||
while (Empty())
|
||||
parser_.notEmpty_.wait(lock);
|
||||
|
||||
return *src_;
|
||||
}
|
||||
|
||||
char Take() {
|
||||
std::unique_lock<std::mutex> lock(parser_.mutex_);
|
||||
|
||||
// If nothing in stream, block to wait.
|
||||
while (Empty())
|
||||
parser_.notEmpty_.wait(lock);
|
||||
|
||||
count_++;
|
||||
char c = *src_++;
|
||||
|
||||
// If all stream is read up, notify that the stream is finish.
|
||||
if (Empty())
|
||||
parser_.finish_.notify_one();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
size_t Tell() const { return count_; }
|
||||
|
||||
// Not implemented
|
||||
char* PutBegin() { return 0; }
|
||||
void Put(char) {}
|
||||
void Flush() {}
|
||||
size_t PutEnd(char*) { return 0; }
|
||||
|
||||
bool Empty() const { return src_ == end_; }
|
||||
|
||||
AsyncDocumentParser& parser_;
|
||||
const char* src_; //!< Current read position.
|
||||
const char* end_; //!< End of buffer
|
||||
size_t count_; //!< Number of characters taken so far.
|
||||
};
|
||||
|
||||
AsyncStringStream stream_;
|
||||
Document& d_;
|
||||
std::thread parseThread_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable notEmpty_;
|
||||
std::condition_variable finish_;
|
||||
bool completed_;
|
||||
};
|
||||
|
||||
int main() {
|
||||
Document d;
|
||||
|
||||
{
|
||||
AsyncDocumentParser<> parser(d);
|
||||
|
||||
const char json1[] = " { \"hello\" : \"world\", \"t\" : tr";
|
||||
//const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // Fot test parsing error
|
||||
const char json2[] = "ue, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.14";
|
||||
const char json3[] = "16, \"a\":[1, 2, 3, 4] } ";
|
||||
|
||||
parser.ParsePart(json1, sizeof(json1) - 1);
|
||||
parser.ParsePart(json2, sizeof(json2) - 1);
|
||||
parser.ParsePart(json3, sizeof(json3) - 1);
|
||||
}
|
||||
|
||||
if (d.HasParseError()) {
|
||||
std::cout << "Error at offset " << d.GetErrorOffset() << ": " << GetParseError_En(d.GetParseError()) << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Stringify the JSON to cout
|
||||
OStreamWrapper os(std::cout);
|
||||
Writer<OStreamWrapper> writer(os);
|
||||
d.Accept(writer);
|
||||
std::cout << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#else // Not supporting C++11
|
||||
|
||||
#include <iostream>
|
||||
int main() {
|
||||
std::cout << "This example requires C++11 compiler" << std::endl;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,30 +0,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 +0,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,72 +0,0 @@
|
||||
// Schema Validator example
|
||||
|
||||
// The example validates JSON text from stdin with a JSON schema specified in the argument.
|
||||
|
||||
#include "rapidjson/error/en.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/schema.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Read a JSON schema from file into Document
|
||||
Document d;
|
||||
char buffer[4096];
|
||||
|
||||
{
|
||||
FILE *fp = fopen(argv[1], "r");
|
||||
if (!fp) {
|
||||
printf("Schema file '%s' not found\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
FileReadStream fs(fp, buffer, sizeof(buffer));
|
||||
d.ParseStream(fs);
|
||||
if (d.HasParseError()) {
|
||||
fprintf(stderr, "Schema file '%s' is not a valid JSON\n", argv[1]);
|
||||
fprintf(stderr, "Error(offset %u): %s\n",
|
||||
static_cast<unsigned>(d.GetErrorOffset()),
|
||||
GetParseError_En(d.GetParseError()));
|
||||
fclose(fp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Then convert the Document into SchemaDocument
|
||||
SchemaDocument sd(d);
|
||||
|
||||
// Use reader to parse the JSON in stdin, and forward SAX events to validator
|
||||
SchemaValidator validator(sd);
|
||||
Reader reader;
|
||||
FileReadStream is(stdin, buffer, sizeof(buffer));
|
||||
if (!reader.Parse(is, validator) && reader.GetParseErrorCode() != kParseErrorTermination) {
|
||||
// Schema validator error would cause kParseErrorTermination, which will handle it in next step.
|
||||
fprintf(stderr, "Input is not a valid JSON\n");
|
||||
fprintf(stderr, "Error(offset %u): %s\n",
|
||||
static_cast<unsigned>(reader.GetErrorOffset()),
|
||||
GetParseError_En(reader.GetParseErrorCode()));
|
||||
}
|
||||
|
||||
// Check the validation result
|
||||
if (validator.IsValid()) {
|
||||
printf("Input JSON is valid.\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
printf("Input JSON is invalid.\n");
|
||||
StringBuffer sb;
|
||||
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
|
||||
fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
|
||||
fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
|
||||
sb.Clear();
|
||||
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
|
||||
fprintf(stderr, "Invalid document: %s\n", sb.GetString());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
@ -1,173 +0,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,29 +0,0 @@
|
||||
// JSON simple example
|
||||
// This example does not handle errors.
|
||||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
int main() {
|
||||
// 1. Parse a JSON string into DOM.
|
||||
const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
|
||||
Document d;
|
||||
d.Parse(json);
|
||||
|
||||
// 2. Modify it by DOM.
|
||||
Value& s = d["stars"];
|
||||
s.SetInt(s.GetInt() + 1);
|
||||
|
||||
// 3. Stringify the DOM
|
||||
StringBuffer buffer;
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
d.Accept(writer);
|
||||
|
||||
// Output {"project":"rapidjson","stars":11}
|
||||
std::cout << buffer.GetString() << std::endl;
|
||||
return 0;
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
#include "rapidjson/reader.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
struct MyHandler {
|
||||
bool Null() { cout << "Null()" << endl; return true; }
|
||||
bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
|
||||
bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
|
||||
bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
|
||||
bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
|
||||
bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
|
||||
bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
|
||||
bool RawNumber(const char* str, SizeType length, bool copy) {
|
||||
cout << "Number(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
|
||||
return true;
|
||||
}
|
||||
bool String(const char* str, SizeType length, bool copy) {
|
||||
cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
|
||||
return true;
|
||||
}
|
||||
bool StartObject() { cout << "StartObject()" << endl; return true; }
|
||||
bool Key(const char* str, SizeType length, bool copy) {
|
||||
cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
|
||||
return true;
|
||||
}
|
||||
bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
|
||||
bool StartArray() { cout << "StartArray()" << endl; return true; }
|
||||
bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
|
||||
};
|
||||
|
||||
int main() {
|
||||
const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
|
||||
|
||||
MyHandler handler;
|
||||
Reader reader;
|
||||
StringStream ss(json);
|
||||
reader.Parse(ss, handler);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
#include "rapidjson/writer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
StringBuffer s;
|
||||
Writer<StringBuffer> writer(s);
|
||||
|
||||
writer.StartObject(); // Between StartObject()/EndObject(),
|
||||
writer.Key("hello"); // output a key,
|
||||
writer.String("world"); // follow by a value.
|
||||
writer.Key("t");
|
||||
writer.Bool(true);
|
||||
writer.Key("f");
|
||||
writer.Bool(false);
|
||||
writer.Key("n");
|
||||
writer.Null();
|
||||
writer.Key("i");
|
||||
writer.Uint(123);
|
||||
writer.Key("pi");
|
||||
writer.Double(3.1416);
|
||||
writer.Key("a");
|
||||
writer.StartArray(); // Between StartArray()/EndArray(),
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
writer.Uint(i); // all values are elements of the array.
|
||||
writer.EndArray();
|
||||
writer.EndObject();
|
||||
|
||||
// {"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}
|
||||
cout << s.GetString() << endl;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,151 +0,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,20 +0,0 @@
|
||||
find_package(GTestSrc)
|
||||
|
||||
IF(GTESTSRC_FOUND)
|
||||
enable_testing()
|
||||
|
||||
if (WIN32 AND (NOT CYGWIN) AND (NOT MINGW))
|
||||
set(gtest_disable_pthreads ON)
|
||||
set(gtest_force_shared_crt ON)
|
||||
endif()
|
||||
|
||||
add_subdirectory(${GTEST_SOURCE_DIR} ${CMAKE_BINARY_DIR}/googletest)
|
||||
include_directories(SYSTEM ${GTEST_INCLUDE_DIR})
|
||||
|
||||
set(TEST_LIBRARIES gtest gtest_main)
|
||||
|
||||
add_custom_target(tests ALL)
|
||||
add_subdirectory(perftest)
|
||||
add_subdirectory(unittest)
|
||||
|
||||
ENDIF(GTESTSRC_FOUND)
|
@ -1,26 +0,0 @@
|
||||
set(PERFTEST_SOURCES
|
||||
misctest.cpp
|
||||
perftest.cpp
|
||||
platformtest.cpp
|
||||
rapidjsontest.cpp
|
||||
schematest.cpp)
|
||||
|
||||
add_executable(perftest ${PERFTEST_SOURCES})
|
||||
target_link_libraries(perftest ${TEST_LIBRARIES})
|
||||
|
||||
add_dependencies(tests perftest)
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -fcolor-diagnostics")
|
||||
endif()
|
||||
endif(CCACHE_FOUND)
|
||||
|
||||
IF(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
add_test(NAME perftest
|
||||
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/perftest
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
|
||||
ENDIF()
|
@ -1,974 +0,0 @@
|
||||
// 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_MISC
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
|
||||
#define protected public
|
||||
#include "rapidjson/writer.h"
|
||||
#undef private
|
||||
|
||||
class Misc : public PerfTest {
|
||||
};
|
||||
|
||||
// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
||||
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
||||
|
||||
#define UTF8_ACCEPT 0
|
||||
#define UTF8_REJECT 12
|
||||
|
||||
static const unsigned char utf8d[] = {
|
||||
// The first part of the table maps bytes to character classes that
|
||||
// to reduce the size of the transition table and create bitmasks.
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||
|
||||
// The second part is a transition table that maps a combination
|
||||
// of a state of the automaton and a character class to a state.
|
||||
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
|
||||
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
|
||||
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
|
||||
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
|
||||
12,36,12,12,12,12,12,12,12,12,12,12,
|
||||
};
|
||||
|
||||
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_F(Misc, Hoehrmann_IsUTF8) {
|
||||
for (size_t i = 0; i < kTrialCount; i++) {
|
||||
EXPECT_TRUE(IsUTF8((unsigned char*)json_));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CountDecimalDigit: Count number of decimal places
|
||||
|
||||
inline unsigned CountDecimalDigit_naive(unsigned n) {
|
||||
unsigned count = 1;
|
||||
while (n >= 10) {
|
||||
n /= 10;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
inline unsigned CountDecimalDigit_enroll4(unsigned n) {
|
||||
unsigned count = 1;
|
||||
while (n >= 10000) {
|
||||
n /= 10000u;
|
||||
count += 4;
|
||||
}
|
||||
if (n < 10) return count;
|
||||
if (n < 100) return count + 1;
|
||||
if (n < 1000) return count + 2;
|
||||
return count + 3;
|
||||
}
|
||||
|
||||
inline unsigned CountDecimalDigit64_enroll4(uint64_t n) {
|
||||
unsigned count = 1;
|
||||
while (n >= 10000) {
|
||||
n /= 10000u;
|
||||
count += 4;
|
||||
}
|
||||
if (n < 10) return count;
|
||||
if (n < 100) return count + 1;
|
||||
if (n < 1000) return count + 2;
|
||||
return count + 3;
|
||||
}
|
||||
|
||||
inline unsigned CountDecimalDigit_fast(unsigned n) {
|
||||
static const uint32_t powers_of_10[] = {
|
||||
0,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
100000,
|
||||
1000000,
|
||||
10000000,
|
||||
100000000,
|
||||
1000000000
|
||||
};
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64)
|
||||
unsigned long i = 0;
|
||||
_BitScanReverse(&i, n | 1);
|
||||
uint32_t t = (i + 1) * 1233 >> 12;
|
||||
#elif defined(__GNUC__)
|
||||
uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12;
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
return t - (n < powers_of_10[t]) + 1;
|
||||
}
|
||||
|
||||
inline unsigned CountDecimalDigit64_fast(uint64_t n) {
|
||||
static const uint64_t powers_of_10[] = {
|
||||
0,
|
||||
10,
|
||||
100,
|
||||
1000,
|
||||
10000,
|
||||
100000,
|
||||
1000000,
|
||||
10000000,
|
||||
100000000,
|
||||
1000000000,
|
||||
10000000000,
|
||||
100000000000,
|
||||
1000000000000,
|
||||
10000000000000,
|
||||
100000000000000,
|
||||
1000000000000000,
|
||||
10000000000000000,
|
||||
100000000000000000,
|
||||
1000000000000000000,
|
||||
10000000000000000000U
|
||||
};
|
||||
|
||||
#if defined(_M_IX86)
|
||||
uint64_t m = n | 1;
|
||||
unsigned long i = 0;
|
||||
if (_BitScanReverse(&i, m >> 32))
|
||||
i += 32;
|
||||
else
|
||||
_BitScanReverse(&i, m & 0xFFFFFFFF);
|
||||
uint32_t t = (i + 1) * 1233 >> 12;
|
||||
#elif defined(_M_X64)
|
||||
unsigned long i = 0;
|
||||
_BitScanReverse64(&i, n | 1);
|
||||
uint32_t t = (i + 1) * 1233 >> 12;
|
||||
#elif defined(__GNUC__)
|
||||
uint32_t t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12;
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
|
||||
return t - (n < powers_of_10[t]) + 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Exhaustive, very slow
|
||||
TEST_F(Misc, CountDecimalDigit_Verify) {
|
||||
unsigned i = 0;
|
||||
do {
|
||||
if (i % (65536 * 256) == 0)
|
||||
printf("%u\n", i);
|
||||
ASSERT_EQ(CountDecimalDigit_enroll4(i), CountDecimalDigit_fast(i));
|
||||
i++;
|
||||
} while (i != 0);
|
||||
}
|
||||
|
||||
static const unsigned kDigits10Trial = 1000000000u;
|
||||
TEST_F(Misc, CountDecimalDigit_naive) {
|
||||
unsigned sum = 0;
|
||||
for (unsigned i = 0; i < kDigits10Trial; i++)
|
||||
sum += CountDecimalDigit_naive(i);
|
||||
printf("%u\n", sum);
|
||||
}
|
||||
|
||||
TEST_F(Misc, CountDecimalDigit_enroll4) {
|
||||
unsigned sum = 0;
|
||||
for (unsigned i = 0; i < kDigits10Trial; i++)
|
||||
sum += CountDecimalDigit_enroll4(i);
|
||||
printf("%u\n", sum);
|
||||
}
|
||||
|
||||
TEST_F(Misc, CountDecimalDigit_fast) {
|
||||
unsigned sum = 0;
|
||||
for (unsigned i = 0; i < kDigits10Trial; i++)
|
||||
sum += CountDecimalDigit_fast(i);
|
||||
printf("%u\n", sum);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(Misc, CountDecimalDigit64_VerifyFast) {
|
||||
uint64_t i = 1, j;
|
||||
do {
|
||||
//printf("%" PRIu64 "\n", i);
|
||||
ASSERT_EQ(CountDecimalDigit64_enroll4(i), CountDecimalDigit64_fast(i));
|
||||
j = i;
|
||||
i *= 3;
|
||||
} while (j < i);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// integer-to-string conversion
|
||||
|
||||
// https://gist.github.com/anonymous/7179097
|
||||
static const int randval[] ={
|
||||
936116, 369532, 453755, -72860, 209713, 268347, 435278, -360266, -416287, -182064,
|
||||
-644712, 944969, 640463, -366588, 471577, -69401, -744294, -505829, 923883, 831785,
|
||||
-601136, -636767, -437054, 591718, 100758, 231907, -719038, 973540, -605220, 506659,
|
||||
-871653, 462533, 764843, -919138, 404305, -630931, -288711, -751454, -173726, -718208,
|
||||
432689, -281157, 360737, 659827, 19174, -376450, 769984, -858198, 439127, 734703,
|
||||
-683426, 7, 386135, 186997, -643900, -744422, -604708, -629545, 42313, -933592,
|
||||
-635566, 182308, 439024, -367219, -73924, -516649, 421935, -470515, 413507, -78952,
|
||||
-427917, -561158, 737176, 94538, 572322, 405217, 709266, -357278, -908099, -425447,
|
||||
601119, 750712, -862285, -177869, 900102, 384877, 157859, -641680, 503738, -702558,
|
||||
278225, 463290, 268378, -212840, 580090, 347346, -473985, -950968, -114547, -839893,
|
||||
-738032, -789424, 409540, 493495, 432099, 119755, 905004, -174834, 338266, 234298,
|
||||
74641, -965136, -754593, 685273, 466924, 920560, 385062, 796402, -67229, 994864,
|
||||
376974, 299869, -647540, -128724, 469890, -163167, -547803, -743363, 486463, -621028,
|
||||
612288, 27459, -514224, 126342, -66612, 803409, -777155, -336453, -284002, 472451,
|
||||
342390, -163630, 908356, -456147, -825607, 268092, -974715, 287227, 227890, -524101,
|
||||
616370, -782456, 922098, -624001, -813690, 171605, -192962, 796151, 707183, -95696,
|
||||
-23163, -721260, 508892, 430715, 791331, 482048, -996102, 863274, 275406, -8279,
|
||||
-556239, -902076, 268647, -818565, 260069, -798232, -172924, -566311, -806503, -885992,
|
||||
813969, -78468, 956632, 304288, 494867, -508784, 381751, 151264, 762953, 76352,
|
||||
594902, 375424, 271700, -743062, 390176, 924237, 772574, 676610, 435752, -153847,
|
||||
3959, -971937, -294181, -538049, -344620, -170136, 19120, -703157, 868152, -657961,
|
||||
-818631, 219015, -872729, -940001, -956570, 880727, -345910, 942913, -942271, -788115,
|
||||
225294, 701108, -517736, -416071, 281940, 488730, 942698, 711494, 838382, -892302,
|
||||
-533028, 103052, 528823, 901515, 949577, 159364, 718227, -241814, -733661, -462928,
|
||||
-495829, 165170, 513580, -629188, -509571, -459083, 198437, 77198, -644612, 811276,
|
||||
-422298, -860842, -52584, 920369, 686424, -530667, -243476, 49763, 345866, -411960,
|
||||
-114863, 470810, -302860, 683007, -509080, 2, -174981, -772163, -48697, 447770,
|
||||
-268246, 213268, 269215, 78810, -236340, -639140, -864323, 505113, -986569, -325215,
|
||||
541859, 163070, -819998, -645161, -583336, 573414, 696417, -132375, 3, -294501,
|
||||
320435, 682591, 840008, 351740, 426951, 609354, 898154, -943254, 227321, -859793,
|
||||
-727993, 44137, -497965, -782239, 14955, -746080, -243366, 9837, -233083, 606507,
|
||||
-995864, -615287, -994307, 602715, 770771, -315040, 610860, 446102, -307120, 710728,
|
||||
-590392, -230474, -762625, -637525, 134963, -202700, -766902, -985541, 218163, 682009,
|
||||
926051, 525156, -61195, 403211, -810098, 245539, -431733, 179998, -806533, 745943,
|
||||
447597, 131973, -187130, 826019, 286107, -937230, -577419, 20254, 681802, -340500,
|
||||
323080, 266283, -667617, 309656, 416386, 611863, 759991, -534257, 523112, -634892,
|
||||
-169913, -204905, -909867, -882185, -944908, 741811, -717675, 967007, -317396, 407230,
|
||||
-412805, 792905, 994873, 744793, -456797, 713493, 355232, 116900, -945199, 880539,
|
||||
342505, -580824, -262273, 982968, -349497, -735488, 311767, -455191, 570918, 389734,
|
||||
-958386, 10262, -99267, 155481, 304210, 204724, 704367, -144893, -233664, -671441,
|
||||
896849, 408613, 762236, 322697, 981321, 688476, 13663, -970704, -379507, 896412,
|
||||
977084, 348869, 875948, 341348, 318710, 512081, 6163, 669044, 833295, 811883,
|
||||
708756, -802534, -536057, 608413, -389625, -694603, 541106, -110037, 720322, -540581,
|
||||
645420, 32980, 62442, 510157, -981870, -87093, -325960, -500494, -718291, -67889,
|
||||
991501, 374804, 769026, -978869, 294747, 714623, 413327, -199164, 671368, 804789,
|
||||
-362507, 798196, -170790, -568895, -869379, 62020, -316693, -837793, 644994, -39341,
|
||||
-417504, -243068, -957756, 99072, 622234, -739992, 225668, 8863, -505910, 82483,
|
||||
-559244, 241572, 1315, -36175, -54990, 376813, -11, 162647, -688204, -486163,
|
||||
-54934, -197470, 744223, -762707, 732540, 996618, 351561, -445933, -898491, 486531,
|
||||
456151, 15276, 290186, -817110, -52995, 313046, -452533, -96267, 94470, -500176,
|
||||
-818026, -398071, -810548, -143325, -819741, 1338, -897676, -101577, -855445, 37309,
|
||||
285742, 953804, -777927, -926962, -811217, -936744, -952245, -802300, -490188, -964953,
|
||||
-552279, 329142, -570048, -505756, 682898, -381089, -14352, 175138, 152390, -582268,
|
||||
-485137, 717035, 805329, 239572, -730409, 209643, -184403, -385864, 675086, 819648,
|
||||
629058, -527109, -488666, -171981, 532788, 552441, 174666, 984921, 766514, 758787,
|
||||
716309, 338801, -978004, -412163, 876079, -734212, 789557, -160491, -522719, 56644,
|
||||
-991, -286038, -53983, 663740, 809812, 919889, -717502, -137704, 220511, 184396,
|
||||
-825740, -588447, 430870, 124309, 135956, 558662, -307087, -788055, -451328, 812260,
|
||||
931601, 324347, -482989, -117858, -278861, 189068, -172774, 929057, 293787, 198161,
|
||||
-342386, -47173, 906555, -759955, -12779, 777604, -97869, 899320, 927486, -25284,
|
||||
-848550, 259450, -485856, -17820, 88, 171400, 235492, -326783, -340793, 886886,
|
||||
112428, -246280, 5979, 648444, -114982, 991013, -56489, -9497, 419706, 632820,
|
||||
-341664, 393926, -848977, -22538, 257307, 773731, -905319, 491153, 734883, -868212,
|
||||
-951053, 644458, -580758, 764735, 584316, 297077, 28852, -397710, -953669, 201772,
|
||||
879050, -198237, -588468, 448102, -116837, 770007, -231812, 642906, -582166, -885828,
|
||||
9, 305082, -996577, 303559, 75008, -772956, -447960, 599825, -295552, 870739,
|
||||
-386278, -950300, 485359, -457081, 629461, -850276, 550496, -451755, -620841, -11766,
|
||||
-950137, 832337, 28711, -273398, -507197, 91921, -271360, -705991, -753220, -388968,
|
||||
967945, 340434, -320883, -662793, -554617, -574568, 477946, -6148, -129519, 689217,
|
||||
920020, -656315, -974523, -212525, 80921, -612532, 645096, 545655, 655713, -591631,
|
||||
-307385, -816688, -618823, -113713, 526430, 673063, 735916, -809095, -850417, 639004,
|
||||
432281, -388185, 270708, 860146, -39902, -786157, -258180, -246169, -966720, -264957,
|
||||
548072, -306010, -57367, -635665, 933824, 70553, -989936, -488741, 72411, -452509,
|
||||
529831, 956277, 449019, -577850, -360986, -803418, 48833, 296073, 203430, 609591,
|
||||
715483, 470964, 658106, -718254, -96424, 790163, 334739, 181070, -373578, 5,
|
||||
-435088, 329841, 330939, -256602, 394355, 912412, 231910, 927278, -661933, 788539,
|
||||
-769664, -893274, -96856, 298205, 901043, -608122, -527430, 183618, -553963, -35246,
|
||||
-393924, 948832, -483198, 594501, 35460, -407007, 93494, -336881, -634072, 984205,
|
||||
-812161, 944664, -31062, 753872, 823933, -69566, 50445, 290147, 85134, 34706,
|
||||
551902, 405202, -991246, -84642, 154341, 316432, -695101, -651588, -5030, 137564,
|
||||
-294665, 332541, 528307, -90572, -344923, 523766, -758498, -968047, 339028, 494578,
|
||||
593129, -725773, 31834, -718406, -208638, 159665, -2043, 673344, -442767, 75816,
|
||||
755442, 769257, -158730, -410272, 691688, 589550, -878398, -184121, 460679, 346312,
|
||||
294163, -544602, 653308, 254167, -276979, 52073, -892684, 887653, -41222, 983065,
|
||||
-68258, -408799, -99069, -674069, -863635, -32890, 622757, -743862, 40872, -4837,
|
||||
-967228, 522370, -903951, -818669, 524459, 514702, 925801, 20007, -299229, 579348,
|
||||
626021, 430089, 348139, -562692, -607728, -130606, -928451, -424793, -458647, -448892,
|
||||
-312230, 143337, 109746, 880042, -339658, -785614, 938995, 540916, 118429, 661351,
|
||||
-402967, 404729, -40918, -976535, 743230, 713110, 440182, -381314, -499252, 74613,
|
||||
193652, 912717, 491323, 583633, 324691, 459397, 281253, 195540, -2764, -888651,
|
||||
892449, 132663, -478373, -430002, -314551, 527826, 247165, 557966, 554778, 481531,
|
||||
-946634, 431685, -769059, -348371, 174046, 184597, -354867, 584422, 227390, -850397,
|
||||
-542924, -849093, -737769, 325359, 736314, 269101, 767940, 674809, 81413, -447458,
|
||||
445076, 189072, 906218, 502688, -718476, -863827, -731381, 100660, 623249, 710008,
|
||||
572060, 922203, 685740, 55096, 263394, -243695, -353910, -516788, 388471, 455165,
|
||||
844103, -643772, 363976, 268875, -899450, 104470, 104029, -238874, -274659, 732969,
|
||||
-676443, 953291, -916289, -861849, -242344, 958083, -479593, -970395, 799831, 277841,
|
||||
-243236, -283462, -201510, 166263, -259105, -575706, 878926, 891064, 895297, 655262,
|
||||
-34807, -809833, -89281, 342585, 554920, 1, 902141, -333425, 139703, 852318,
|
||||
-618438, 329498, -932596, -692836, -513372, 733656, -523411, 85779, 500478, -682697,
|
||||
-502836, 138776, 156341, -420037, -557964, -556378, 710993, -50383, -877159, 916334,
|
||||
132996, 583516, -603392, -111615, -12288, -780214, 476780, 123327, 137607, 519956,
|
||||
745837, 17358, -158581, -53490
|
||||
};
|
||||
static const size_t randvalCount = sizeof(randval) / sizeof(randval[0]);
|
||||
static const size_t kItoaTrialCount = 10000;
|
||||
|
||||
static const char digits[201] =
|
||||
"0001020304050607080910111213141516171819"
|
||||
"2021222324252627282930313233343536373839"
|
||||
"4041424344454647484950515253545556575859"
|
||||
"6061626364656667686970717273747576777879"
|
||||
"8081828384858687888990919293949596979899";
|
||||
|
||||
// Prevent code being optimized out
|
||||
//#define OUTPUT_LENGTH(length) printf("", length)
|
||||
#define OUTPUT_LENGTH(length) printf("%u\n", (unsigned)length)
|
||||
|
||||
template<typename OutputStream>
|
||||
class Writer1 {
|
||||
public:
|
||||
Writer1() : os_() {}
|
||||
Writer1(OutputStream& os) : os_(&os) {}
|
||||
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
os_->Put('-');
|
||||
i = -i;
|
||||
}
|
||||
return WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
os_->Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u64 % 10) + '0';
|
||||
u64 /= 10;
|
||||
} while (u64 > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
OutputStream* os_;
|
||||
};
|
||||
|
||||
template<>
|
||||
bool Writer1<rapidjson::StringBuffer>::WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char* p = buffer;
|
||||
do {
|
||||
*p++ = char(u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
char* d = os_->Push(p - buffer);
|
||||
do {
|
||||
--p;
|
||||
*d++ = *p;
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Using digits LUT to reduce divsion/modulo
|
||||
template<typename OutputStream>
|
||||
class Writer2 {
|
||||
public:
|
||||
Writer2() : os_() {}
|
||||
Writer2(OutputStream& os) : os_(&os) {}
|
||||
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
os_->Put('-');
|
||||
i = -i;
|
||||
}
|
||||
return WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char* p = buffer;
|
||||
while (u >= 100) {
|
||||
const unsigned i = (u % 100) << 1;
|
||||
u /= 100;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
if (u < 10)
|
||||
*p++ = char(u) + '0';
|
||||
else {
|
||||
const unsigned i = u << 1;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
os_->Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char* p = buffer;
|
||||
while (u64 >= 100) {
|
||||
const unsigned i = static_cast<unsigned>(u64 % 100) << 1;
|
||||
u64 /= 100;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
if (u64 < 10)
|
||||
*p++ = char(u64) + '0';
|
||||
else {
|
||||
const unsigned i = static_cast<unsigned>(u64) << 1;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
OutputStream* os_;
|
||||
};
|
||||
|
||||
// First pass to count digits
|
||||
template<typename OutputStream>
|
||||
class Writer3 {
|
||||
public:
|
||||
Writer3() : os_() {}
|
||||
Writer3(OutputStream& os) : os_(&os) {}
|
||||
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
os_->Put('-');
|
||||
i = -i;
|
||||
}
|
||||
return WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
os_->Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char *p = buffer;
|
||||
do {
|
||||
*p++ = char(u64 % 10) + '0';
|
||||
u64 /= 10;
|
||||
} while (u64 > 0);
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void WriteUintReverse(char* d, unsigned u) {
|
||||
do {
|
||||
*--d = char(u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
}
|
||||
|
||||
void WriteUint64Reverse(char* d, uint64_t u) {
|
||||
do {
|
||||
*--d = char(u % 10) + '0';
|
||||
u /= 10;
|
||||
} while (u > 0);
|
||||
}
|
||||
|
||||
OutputStream* os_;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool Writer3<rapidjson::StringBuffer>::WriteUint(unsigned u) {
|
||||
unsigned digit = CountDecimalDigit_fast(u);
|
||||
WriteUintReverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer3<rapidjson::InsituStringStream>::WriteUint(unsigned u) {
|
||||
unsigned digit = CountDecimalDigit_fast(u);
|
||||
WriteUintReverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer3<rapidjson::StringBuffer>::WriteUint64(uint64_t u) {
|
||||
unsigned digit = CountDecimalDigit64_fast(u);
|
||||
WriteUint64Reverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer3<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
|
||||
unsigned digit = CountDecimalDigit64_fast(u);
|
||||
WriteUint64Reverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Using digits LUT to reduce divsion/modulo, two passes
|
||||
template<typename OutputStream>
|
||||
class Writer4 {
|
||||
public:
|
||||
Writer4() : os_() {}
|
||||
Writer4(OutputStream& os) : os_(&os) {}
|
||||
|
||||
void Reset(OutputStream& os) {
|
||||
os_ = &os;
|
||||
}
|
||||
|
||||
bool WriteInt(int i) {
|
||||
if (i < 0) {
|
||||
os_->Put('-');
|
||||
i = -i;
|
||||
}
|
||||
return WriteUint((unsigned)i);
|
||||
}
|
||||
|
||||
bool WriteUint(unsigned u) {
|
||||
char buffer[10];
|
||||
char* p = buffer;
|
||||
while (u >= 100) {
|
||||
const unsigned i = (u % 100) << 1;
|
||||
u /= 100;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
if (u < 10)
|
||||
*p++ = char(u) + '0';
|
||||
else {
|
||||
const unsigned i = u << 1;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteInt64(int64_t i64) {
|
||||
if (i64 < 0) {
|
||||
os_->Put('-');
|
||||
i64 = -i64;
|
||||
}
|
||||
WriteUint64((uint64_t)i64);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteUint64(uint64_t u64) {
|
||||
char buffer[20];
|
||||
char* p = buffer;
|
||||
while (u64 >= 100) {
|
||||
const unsigned i = static_cast<unsigned>(u64 % 100) << 1;
|
||||
u64 /= 100;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
if (u64 < 10)
|
||||
*p++ = char(u64) + '0';
|
||||
else {
|
||||
const unsigned i = static_cast<unsigned>(u64) << 1;
|
||||
*p++ = digits[i + 1];
|
||||
*p++ = digits[i];
|
||||
}
|
||||
|
||||
do {
|
||||
--p;
|
||||
os_->Put(*p);
|
||||
} while (p != buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void WriteUintReverse(char* d, unsigned u) {
|
||||
while (u >= 100) {
|
||||
const unsigned i = (u % 100) << 1;
|
||||
u /= 100;
|
||||
*--d = digits[i + 1];
|
||||
*--d = digits[i];
|
||||
}
|
||||
if (u < 10) {
|
||||
*--d = char(u) + '0';
|
||||
}
|
||||
else {
|
||||
const unsigned i = u << 1;
|
||||
*--d = digits[i + 1];
|
||||
*--d = digits[i];
|
||||
}
|
||||
}
|
||||
|
||||
void WriteUint64Reverse(char* d, uint64_t u) {
|
||||
while (u >= 100) {
|
||||
const unsigned i = (u % 100) << 1;
|
||||
u /= 100;
|
||||
*--d = digits[i + 1];
|
||||
*--d = digits[i];
|
||||
}
|
||||
if (u < 10) {
|
||||
*--d = char(u) + '0';
|
||||
}
|
||||
else {
|
||||
const unsigned i = u << 1;
|
||||
*--d = digits[i + 1];
|
||||
*--d = digits[i];
|
||||
}
|
||||
}
|
||||
|
||||
OutputStream* os_;
|
||||
};
|
||||
|
||||
template<>
|
||||
inline bool Writer4<rapidjson::StringBuffer>::WriteUint(unsigned u) {
|
||||
unsigned digit = CountDecimalDigit_fast(u);
|
||||
WriteUintReverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer4<rapidjson::InsituStringStream>::WriteUint(unsigned u) {
|
||||
unsigned digit = CountDecimalDigit_fast(u);
|
||||
WriteUintReverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer4<rapidjson::StringBuffer>::WriteUint64(uint64_t u) {
|
||||
unsigned digit = CountDecimalDigit64_fast(u);
|
||||
WriteUint64Reverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool Writer4<rapidjson::InsituStringStream>::WriteUint64(uint64_t u) {
|
||||
unsigned digit = CountDecimalDigit64_fast(u);
|
||||
WriteUint64Reverse(os_->Push(digit) + digit, u);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void itoa_Writer_StringBufferVerify() {
|
||||
rapidjson::StringBuffer sb;
|
||||
Writer writer(sb);
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%d", randval[j]);
|
||||
writer.WriteInt(randval[j]);
|
||||
ASSERT_STREQ(buffer, sb.GetString());
|
||||
sb.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void itoa_Writer_InsituStringStreamVerify() {
|
||||
Writer writer;
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%d", randval[j]);
|
||||
char buffer2[32];
|
||||
rapidjson::InsituStringStream ss(buffer2);
|
||||
writer.Reset(ss);
|
||||
char* begin = ss.PutBegin();
|
||||
writer.WriteInt(randval[j]);
|
||||
ss.Put('\0');
|
||||
ss.PutEnd(begin);
|
||||
ASSERT_STREQ(buffer, buffer2);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void itoa_Writer_StringBuffer() {
|
||||
size_t length = 0;
|
||||
|
||||
rapidjson::StringBuffer sb;
|
||||
Writer writer(sb);
|
||||
|
||||
for (size_t i = 0; i < kItoaTrialCount; i++) {
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
writer.WriteInt(randval[j]);
|
||||
length += sb.GetSize();
|
||||
sb.Clear();
|
||||
}
|
||||
}
|
||||
OUTPUT_LENGTH(length);
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void itoa_Writer_InsituStringStream() {
|
||||
size_t length = 0;
|
||||
|
||||
char buffer[32];
|
||||
Writer writer;
|
||||
for (size_t i = 0; i < kItoaTrialCount; i++) {
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
rapidjson::InsituStringStream ss(buffer);
|
||||
writer.Reset(ss);
|
||||
char* begin = ss.PutBegin();
|
||||
writer.WriteInt(randval[j]);
|
||||
length += ss.PutEnd(begin);
|
||||
}
|
||||
}
|
||||
OUTPUT_LENGTH(length);
|
||||
};
|
||||
|
||||
template <typename Writer>
|
||||
void itoa64_Writer_StringBufferVerify() {
|
||||
rapidjson::StringBuffer sb;
|
||||
Writer writer(sb);
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
char buffer[32];
|
||||
int64_t x = randval[j] * randval[j];
|
||||
sprintf(buffer, "%" PRIi64, x);
|
||||
writer.WriteInt64(x);
|
||||
ASSERT_STREQ(buffer, sb.GetString());
|
||||
sb.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void itoa64_Writer_InsituStringStreamVerify() {
|
||||
Writer writer;
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
char buffer[32];
|
||||
int64_t x = randval[j] * randval[j];
|
||||
sprintf(buffer, "%" PRIi64, x);
|
||||
char buffer2[32];
|
||||
rapidjson::InsituStringStream ss(buffer2);
|
||||
writer.Reset(ss);
|
||||
char* begin = ss.PutBegin();
|
||||
writer.WriteInt64(x);
|
||||
ss.Put('\0');
|
||||
ss.PutEnd(begin);
|
||||
ASSERT_STREQ(buffer, buffer2);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void itoa64_Writer_StringBuffer() {
|
||||
size_t length = 0;
|
||||
|
||||
rapidjson::StringBuffer sb;
|
||||
Writer writer(sb);
|
||||
|
||||
for (size_t i = 0; i < kItoaTrialCount; i++) {
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
writer.WriteInt64(randval[j] * randval[j]);
|
||||
length += sb.GetSize();
|
||||
sb.Clear();
|
||||
}
|
||||
}
|
||||
OUTPUT_LENGTH(length);
|
||||
}
|
||||
|
||||
template <typename Writer>
|
||||
void itoa64_Writer_InsituStringStream() {
|
||||
size_t length = 0;
|
||||
|
||||
char buffer[32];
|
||||
Writer writer;
|
||||
for (size_t i = 0; i < kItoaTrialCount; i++) {
|
||||
for (size_t j = 0; j < randvalCount; j++) {
|
||||
rapidjson::InsituStringStream ss(buffer);
|
||||
writer.Reset(ss);
|
||||
char* begin = ss.PutBegin();
|
||||
writer.WriteInt64(randval[j] * randval[j]);
|
||||
length += ss.PutEnd(begin);
|
||||
}
|
||||
}
|
||||
OUTPUT_LENGTH(length);
|
||||
};
|
||||
|
||||
// Full specialization for InsituStringStream to prevent memory copying
|
||||
// (normally we will not use InsituStringStream for writing, just for testing)
|
||||
|
||||
namespace rapidjson {
|
||||
|
||||
template<>
|
||||
bool rapidjson::Writer<InsituStringStream>::WriteInt(int i) {
|
||||
char *buffer = os_->Push(11);
|
||||
const char* end = internal::i32toa(i, buffer);
|
||||
os_->Pop(11 - (end - buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Writer<InsituStringStream>::WriteUint(unsigned u) {
|
||||
char *buffer = os_->Push(10);
|
||||
const char* end = internal::u32toa(u, buffer);
|
||||
os_->Pop(10 - (end - buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Writer<InsituStringStream>::WriteInt64(int64_t i64) {
|
||||
char *buffer = os_->Push(21);
|
||||
const char* end = internal::i64toa(i64, buffer);
|
||||
os_->Pop(21 - (end - buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool Writer<InsituStringStream>::WriteUint64(uint64_t u) {
|
||||
char *buffer = os_->Push(20);
|
||||
const char* end = internal::u64toa(u, buffer);
|
||||
os_->Pop(20 - (end - buffer));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace rapidjson
|
||||
|
||||
TEST_F(Misc, itoa_Writer_StringBufferVerify) { itoa_Writer_StringBufferVerify<rapidjson::Writer<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer1_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer1<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer2_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer2<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer3_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer3<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer4_StringBufferVerify) { itoa_Writer_StringBufferVerify<Writer4<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer1_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer1<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer2_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer2<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer3_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer3<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer4_InsituStringStreamVerify) { itoa_Writer_InsituStringStreamVerify<Writer4<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer_StringBuffer) { itoa_Writer_StringBuffer<rapidjson::Writer<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer1_StringBuffer) { itoa_Writer_StringBuffer<Writer1<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer2_StringBuffer) { itoa_Writer_StringBuffer<Writer2<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer3_StringBuffer) { itoa_Writer_StringBuffer<Writer3<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer4_StringBuffer) { itoa_Writer_StringBuffer<Writer4<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa_Writer_InsituStringStream) { itoa_Writer_InsituStringStream<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer1_InsituStringStream) { itoa_Writer_InsituStringStream<Writer1<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer2_InsituStringStream) { itoa_Writer_InsituStringStream<Writer2<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer3_InsituStringStream) { itoa_Writer_InsituStringStream<Writer3<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa_Writer4_InsituStringStream) { itoa_Writer_InsituStringStream<Writer4<rapidjson::InsituStringStream> >(); }
|
||||
|
||||
TEST_F(Misc, itoa64_Writer_StringBufferVerify) { itoa64_Writer_StringBufferVerify<rapidjson::Writer<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer1_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer1<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer2_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer2<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer3_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer3<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer4_StringBufferVerify) { itoa64_Writer_StringBufferVerify<Writer4<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer1_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer1<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer2_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer2<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer3_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer3<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer4_InsituStringStreamVerify) { itoa64_Writer_InsituStringStreamVerify<Writer4<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer_StringBuffer) { itoa64_Writer_StringBuffer<rapidjson::Writer<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer1_StringBuffer) { itoa64_Writer_StringBuffer<Writer1<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer2_StringBuffer) { itoa64_Writer_StringBuffer<Writer2<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer3_StringBuffer) { itoa64_Writer_StringBuffer<Writer3<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer4_StringBuffer) { itoa64_Writer_StringBuffer<Writer4<rapidjson::StringBuffer> >(); }
|
||||
TEST_F(Misc, itoa64_Writer_InsituStringStream) { itoa64_Writer_InsituStringStream<rapidjson::Writer<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer1_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer1<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer2_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer2<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer3_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer3<rapidjson::InsituStringStream> >(); }
|
||||
TEST_F(Misc, itoa64_Writer4_InsituStringStream) { itoa64_Writer_InsituStringStream<Writer4<rapidjson::InsituStringStream> >(); }
|
||||
|
||||
#endif // TEST_MISC
|
@ -1,24 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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
|
@ -1,216 +0,0 @@
|
||||
#include "perftest.h"
|
||||
|
||||
#if TEST_RAPIDJSON
|
||||
|
||||
#include "rapidjson/schema.h"
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template <typename Allocator>
|
||||
static char* ReadFile(const char* filename, Allocator& allocator) {
|
||||
const char *paths[] = {
|
||||
"",
|
||||
"bin/",
|
||||
"../bin/",
|
||||
"../../bin/",
|
||||
"../../../bin/"
|
||||
};
|
||||
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);
|
||||
size_t length = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* json = reinterpret_cast<char*>(allocator.Malloc(length + 1));
|
||||
size_t readLength = fread(json, 1, length, fp);
|
||||
json[readLength] = '\0';
|
||||
fclose(fp);
|
||||
return json;
|
||||
}
|
||||
|
||||
class Schema : public PerfTest {
|
||||
public:
|
||||
Schema() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
PerfTest::SetUp();
|
||||
|
||||
const char* filenames[] = {
|
||||
"additionalItems.json",
|
||||
"additionalProperties.json",
|
||||
"allOf.json",
|
||||
"anyOf.json",
|
||||
"default.json",
|
||||
"definitions.json",
|
||||
"dependencies.json",
|
||||
"enum.json",
|
||||
"items.json",
|
||||
"maximum.json",
|
||||
"maxItems.json",
|
||||
"maxLength.json",
|
||||
"maxProperties.json",
|
||||
"minimum.json",
|
||||
"minItems.json",
|
||||
"minLength.json",
|
||||
"minProperties.json",
|
||||
"multipleOf.json",
|
||||
"not.json",
|
||||
"oneOf.json",
|
||||
"pattern.json",
|
||||
"patternProperties.json",
|
||||
"properties.json",
|
||||
"ref.json",
|
||||
"refRemote.json",
|
||||
"required.json",
|
||||
"type.json",
|
||||
"uniqueItems.json"
|
||||
};
|
||||
|
||||
char jsonBuffer[65536];
|
||||
MemoryPoolAllocator<> jsonAllocator(jsonBuffer, sizeof(jsonBuffer));
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(filenames); i++) {
|
||||
char filename[FILENAME_MAX];
|
||||
sprintf(filename, "jsonschema/tests/draft4/%s", filenames[i]);
|
||||
char* json = ReadFile(filename, jsonAllocator);
|
||||
if (!json) {
|
||||
printf("json test suite file %s not found", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
Document d;
|
||||
d.Parse(json);
|
||||
if (d.HasParseError()) {
|
||||
printf("json test suite file %s has parse error", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) {
|
||||
std::string schemaDescription = (*schemaItr)["description"].GetString();
|
||||
if (IsExcludeTestSuite(schemaDescription))
|
||||
continue;
|
||||
|
||||
TestSuite* ts = new TestSuite;
|
||||
ts->schema = new SchemaDocument((*schemaItr)["schema"]);
|
||||
|
||||
const Value& tests = (*schemaItr)["tests"];
|
||||
for (Value::ConstValueIterator testItr = tests.Begin(); testItr != tests.End(); ++testItr) {
|
||||
if (IsExcludeTest(schemaDescription + ", " + (*testItr)["description"].GetString()))
|
||||
continue;
|
||||
|
||||
Document* d2 = new Document;
|
||||
d2->CopyFrom((*testItr)["data"], d2->GetAllocator());
|
||||
ts->tests.push_back(d2);
|
||||
}
|
||||
testSuites.push_back(ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PerfTest::TearDown();
|
||||
for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr)
|
||||
delete *itr;
|
||||
testSuites.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
// Using the same exclusion in https://github.com/json-schema/JSON-Schema-Test-Suite
|
||||
static bool IsExcludeTestSuite(const std::string& description) {
|
||||
const char* excludeTestSuites[] = {
|
||||
//lost failing these tests
|
||||
"remote ref",
|
||||
"remote ref, containing refs itself",
|
||||
"fragment within remote ref",
|
||||
"ref within remote ref",
|
||||
"change resolution scope",
|
||||
// these below were added to get jsck in the benchmarks)
|
||||
"uniqueItems validation",
|
||||
"valid definition",
|
||||
"invalid definition"
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(excludeTestSuites); i++)
|
||||
if (excludeTestSuites[i] == description)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Using the same exclusion in https://github.com/json-schema/JSON-Schema-Test-Suite
|
||||
static bool IsExcludeTest(const std::string& description) {
|
||||
const char* excludeTests[] = {
|
||||
//lots of validators fail these
|
||||
"invalid definition, invalid definition schema",
|
||||
"maxLength validation, two supplementary Unicode code points is long enough",
|
||||
"minLength validation, one supplementary Unicode code point is not long enough",
|
||||
//this is to get tv4 in the benchmarks
|
||||
"heterogeneous enum validation, something else is invalid"
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(excludeTests); i++)
|
||||
if (excludeTests[i] == description)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
Schema(const Schema&);
|
||||
Schema& operator=(const Schema&);
|
||||
|
||||
protected:
|
||||
typedef std::vector<Document*> DocumentList;
|
||||
|
||||
struct TestSuite {
|
||||
TestSuite() : schema() {}
|
||||
~TestSuite() {
|
||||
delete schema;
|
||||
for (DocumentList::iterator itr = tests.begin(); itr != tests.end(); ++itr)
|
||||
delete *itr;
|
||||
}
|
||||
SchemaDocument* schema;
|
||||
DocumentList tests;
|
||||
};
|
||||
|
||||
typedef std::vector<TestSuite* > TestSuiteList;
|
||||
TestSuiteList testSuites;
|
||||
};
|
||||
|
||||
TEST_F(Schema, TestSuite) {
|
||||
char validatorBuffer[65536];
|
||||
MemoryPoolAllocator<> validatorAllocator(validatorBuffer, sizeof(validatorBuffer));
|
||||
|
||||
const int trialCount = 100000;
|
||||
int testCount = 0;
|
||||
clock_t start = clock();
|
||||
for (int i = 0; i < trialCount; i++) {
|
||||
for (TestSuiteList::const_iterator itr = testSuites.begin(); itr != testSuites.end(); ++itr) {
|
||||
const TestSuite& ts = **itr;
|
||||
GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<> >, MemoryPoolAllocator<> > validator(*ts.schema, &validatorAllocator);
|
||||
for (DocumentList::const_iterator testItr = ts.tests.begin(); testItr != ts.tests.end(); ++testItr) {
|
||||
validator.Reset();
|
||||
(*testItr)->Accept(validator);
|
||||
testCount++;
|
||||
}
|
||||
validatorAllocator.Clear();
|
||||
}
|
||||
}
|
||||
clock_t end = clock();
|
||||
double duration = double(end - start) / CLOCKS_PER_SEC;
|
||||
printf("%d trials in %f s -> %f trials per sec\n", trialCount, duration, trialCount / duration);
|
||||
printf("%d tests per trial\n", testCount / trialCount);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,92 +0,0 @@
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
set(UNITTEST_SOURCES
|
||||
allocatorstest.cpp
|
||||
bigintegertest.cpp
|
||||
documenttest.cpp
|
||||
dtoatest.cpp
|
||||
encodedstreamtest.cpp
|
||||
encodingstest.cpp
|
||||
fwdtest.cpp
|
||||
filestreamtest.cpp
|
||||
itoatest.cpp
|
||||
istreamwrappertest.cpp
|
||||
jsoncheckertest.cpp
|
||||
namespacetest.cpp
|
||||
pointertest.cpp
|
||||
prettywritertest.cpp
|
||||
ostreamwrappertest.cpp
|
||||
readertest.cpp
|
||||
regextest.cpp
|
||||
schematest.cpp
|
||||
simdtest.cpp
|
||||
strfunctest.cpp
|
||||
stringbuffertest.cpp
|
||||
strtodtest.cpp
|
||||
unittest.cpp
|
||||
valuetest.cpp
|
||||
writertest.cpp)
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments -fcolor-diagnostics")
|
||||
endif()
|
||||
endif(CCACHE_FOUND)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
|
||||
# If the user is running a newer version of Clang that includes the
|
||||
# -Wdouble-promotion, we will ignore that warning.
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.7)
|
||||
CHECK_CXX_COMPILER_FLAG("-Wno-double-promotion" HAS_NO_DOUBLE_PROMOTION)
|
||||
if (HAS_NO_DOUBLE_PROMOTION)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-double-promotion")
|
||||
endif()
|
||||
endif()
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# Force to always compile with /W4
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||
endif()
|
||||
|
||||
# Force to always compile with /WX
|
||||
if(CMAKE_CXX_FLAGS MATCHES "/WX-")
|
||||
string(REGEX REPLACE "/WX-" "/WX" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DRAPIDJSON_HAS_STDSTRING=1")
|
||||
|
||||
add_library(namespacetest STATIC namespacetest.cpp)
|
||||
|
||||
add_executable(unittest ${UNITTEST_SOURCES})
|
||||
target_link_libraries(unittest ${TEST_LIBRARIES} namespacetest)
|
||||
|
||||
add_dependencies(tests unittest)
|
||||
|
||||
add_test(NAME unittest
|
||||
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
|
||||
|
||||
if(NOT MSVC)
|
||||
# Not running SIMD.* unit test cases for Valgrind
|
||||
add_test(NAME valgrind_unittest
|
||||
COMMAND valgrind --leak-check=full --error-exitcode=1 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest --gtest_filter=-SIMD.*
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_test(NAME symbol_check
|
||||
COMMAND sh -c "objdump -t -C libnamespacetest.a | grep rapidjson ; test $? -ne 0"
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
||||
endif(NOT MSVC)
|
@ -1,102 +0,0 @@
|
||||
// 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/allocators.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template <typename Allocator>
|
||||
void TestAllocator(Allocator& a) {
|
||||
EXPECT_TRUE(a.Malloc(0) == 0);
|
||||
|
||||
uint8_t* p = static_cast<uint8_t*>(a.Malloc(100));
|
||||
EXPECT_TRUE(p != 0);
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
p[i] = static_cast<uint8_t>(i);
|
||||
|
||||
// Expand
|
||||
uint8_t* q = static_cast<uint8_t*>(a.Realloc(p, 100, 200));
|
||||
EXPECT_TRUE(q != 0);
|
||||
for (size_t i = 0; i < 100; i++)
|
||||
EXPECT_EQ(i, q[i]);
|
||||
for (size_t i = 100; i < 200; i++)
|
||||
q[i] = static_cast<uint8_t>(i);
|
||||
|
||||
// Shrink
|
||||
uint8_t *r = static_cast<uint8_t*>(a.Realloc(q, 200, 150));
|
||||
EXPECT_TRUE(r != 0);
|
||||
for (size_t i = 0; i < 150; i++)
|
||||
EXPECT_EQ(i, r[i]);
|
||||
|
||||
Allocator::Free(r);
|
||||
|
||||
// Realloc to zero size
|
||||
EXPECT_TRUE(a.Realloc(a.Malloc(1), 1, 0) == 0);
|
||||
}
|
||||
|
||||
TEST(Allocator, CrtAllocator) {
|
||||
CrtAllocator a;
|
||||
TestAllocator(a);
|
||||
}
|
||||
|
||||
TEST(Allocator, MemoryPoolAllocator) {
|
||||
MemoryPoolAllocator<> a;
|
||||
TestAllocator(a);
|
||||
|
||||
for (size_t i = 1; i < 1000; i++) {
|
||||
EXPECT_TRUE(a.Malloc(i) != 0);
|
||||
EXPECT_LE(a.Size(), a.Capacity());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Allocator, Alignment) {
|
||||
#if RAPIDJSON_64BIT == 1
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000000), RAPIDJSON_ALIGN(0));
|
||||
for (uint64_t i = 1; i < 8; i++) {
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008), RAPIDJSON_ALIGN(i));
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000000, 0x00000010), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0x00000008) + i));
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x00000001, 0x00000000), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0x00000000, 0xFFFFFFF8) + i));
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF8), RAPIDJSON_ALIGN(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFF0) + i));
|
||||
}
|
||||
#else
|
||||
EXPECT_EQ(0u, RAPIDJSON_ALIGN(0u));
|
||||
for (uint32_t i = 1; i < 4; i++) {
|
||||
EXPECT_EQ(4u, RAPIDJSON_ALIGN(i));
|
||||
EXPECT_EQ(8u, RAPIDJSON_ALIGN(4u + i));
|
||||
EXPECT_EQ(0xFFFFFFF8u, RAPIDJSON_ALIGN(0xFFFFFFF4u + i));
|
||||
EXPECT_EQ(0xFFFFFFFCu, RAPIDJSON_ALIGN(0xFFFFFFF8u + i));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Allocator, Issue399) {
|
||||
MemoryPoolAllocator<> a;
|
||||
void* p = a.Malloc(100);
|
||||
void* q = a.Realloc(p, 100, 200);
|
||||
EXPECT_EQ(p, q);
|
||||
|
||||
// exhuasive testing
|
||||
for (size_t j = 1; j < 32; j++) {
|
||||
a.Clear();
|
||||
a.Malloc(j); // some unaligned size
|
||||
p = a.Malloc(1);
|
||||
for (size_t i = 1; i < 1024; i++) {
|
||||
q = a.Realloc(p, i, i + 1);
|
||||
EXPECT_EQ(p, q);
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
// 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/internal/biginteger.h"
|
||||
|
||||
using namespace rapidjson::internal;
|
||||
|
||||
#define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1)
|
||||
|
||||
static const BigInteger kZero(0);
|
||||
static const BigInteger kOne(1);
|
||||
static const BigInteger kUint64Max = BIGINTEGER_LITERAL("18446744073709551615");
|
||||
static const BigInteger kTwo64 = BIGINTEGER_LITERAL("18446744073709551616");
|
||||
|
||||
TEST(BigInteger, Constructor) {
|
||||
EXPECT_TRUE(kZero.IsZero());
|
||||
EXPECT_TRUE(kZero == kZero);
|
||||
EXPECT_TRUE(kZero == BIGINTEGER_LITERAL("0"));
|
||||
EXPECT_TRUE(kZero == BIGINTEGER_LITERAL("00"));
|
||||
|
||||
const BigInteger a(123);
|
||||
EXPECT_TRUE(a == a);
|
||||
EXPECT_TRUE(a == BIGINTEGER_LITERAL("123"));
|
||||
EXPECT_TRUE(a == BIGINTEGER_LITERAL("0123"));
|
||||
|
||||
EXPECT_EQ(2u, kTwo64.GetCount());
|
||||
EXPECT_EQ(0u, kTwo64.GetDigit(0));
|
||||
EXPECT_EQ(1u, kTwo64.GetDigit(1));
|
||||
}
|
||||
|
||||
TEST(BigInteger, AddUint64) {
|
||||
BigInteger a = kZero;
|
||||
a += 0u;
|
||||
EXPECT_TRUE(kZero == a);
|
||||
|
||||
a += 1u;
|
||||
EXPECT_TRUE(kOne == a);
|
||||
|
||||
a += 1u;
|
||||
EXPECT_TRUE(BigInteger(2) == a);
|
||||
|
||||
EXPECT_TRUE(BigInteger(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)) == kUint64Max);
|
||||
BigInteger b = kUint64Max;
|
||||
b += 1u;
|
||||
EXPECT_TRUE(kTwo64 == b);
|
||||
b += RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF);
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("36893488147419103231") == b);
|
||||
}
|
||||
|
||||
TEST(BigInteger, MultiplyUint64) {
|
||||
BigInteger a = kZero;
|
||||
a *= static_cast <uint64_t>(0);
|
||||
EXPECT_TRUE(kZero == a);
|
||||
a *= static_cast <uint64_t>(123);
|
||||
EXPECT_TRUE(kZero == a);
|
||||
|
||||
BigInteger b = kOne;
|
||||
b *= static_cast<uint64_t>(1);
|
||||
EXPECT_TRUE(kOne == b);
|
||||
b *= static_cast<uint64_t>(0);
|
||||
EXPECT_TRUE(kZero == b);
|
||||
|
||||
BigInteger c(123);
|
||||
c *= static_cast<uint64_t>(456u);
|
||||
EXPECT_TRUE(BigInteger(123u * 456u) == c);
|
||||
c *= RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF);
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("1034640981606221330982120") == c);
|
||||
c *= RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF);
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("19085757395861596536664473018420572782123800") == c);
|
||||
}
|
||||
|
||||
TEST(BigInteger, MultiplyUint32) {
|
||||
BigInteger a = kZero;
|
||||
a *= static_cast <uint32_t>(0);
|
||||
EXPECT_TRUE(kZero == a);
|
||||
a *= static_cast <uint32_t>(123);
|
||||
EXPECT_TRUE(kZero == a);
|
||||
|
||||
BigInteger b = kOne;
|
||||
b *= static_cast<uint32_t>(1);
|
||||
EXPECT_TRUE(kOne == b);
|
||||
b *= static_cast<uint32_t>(0);
|
||||
EXPECT_TRUE(kZero == b);
|
||||
|
||||
BigInteger c(123);
|
||||
c *= static_cast<uint32_t>(456u);
|
||||
EXPECT_TRUE(BigInteger(123u * 456u) == c);
|
||||
c *= 0xFFFFFFFFu;
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("240896125641960") == c);
|
||||
c *= 0xFFFFFFFFu;
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("1034640981124429079698200") == c);
|
||||
}
|
||||
|
||||
TEST(BigInteger, LeftShift) {
|
||||
BigInteger a = kZero;
|
||||
a <<= 1;
|
||||
EXPECT_TRUE(kZero == a);
|
||||
a <<= 64;
|
||||
EXPECT_TRUE(kZero == a);
|
||||
|
||||
a = BigInteger(123);
|
||||
a <<= 0;
|
||||
EXPECT_TRUE(BigInteger(123) == a);
|
||||
a <<= 1;
|
||||
EXPECT_TRUE(BigInteger(246) == a);
|
||||
a <<= 64;
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("4537899042132549697536") == a);
|
||||
a <<= 99;
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("2876235222267216943024851750785644982682875244576768") == a);
|
||||
}
|
||||
|
||||
TEST(BigInteger, Compare) {
|
||||
EXPECT_EQ(0, kZero.Compare(kZero));
|
||||
EXPECT_EQ(1, kOne.Compare(kZero));
|
||||
EXPECT_EQ(-1, kZero.Compare(kOne));
|
||||
EXPECT_EQ(0, kUint64Max.Compare(kUint64Max));
|
||||
EXPECT_EQ(0, kTwo64.Compare(kTwo64));
|
||||
EXPECT_EQ(-1, kUint64Max.Compare(kTwo64));
|
||||
EXPECT_EQ(1, kTwo64.Compare(kUint64Max));
|
||||
}
|
@ -1,652 +0,0 @@
|
||||
// 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/writer.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
RAPIDJSON_DIAG_OFF(missing-variable-declarations)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
template <typename DocumentType>
|
||||
void ParseCheck(DocumentType& doc) {
|
||||
typedef typename DocumentType::ValueType ValueType;
|
||||
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
if (doc.HasParseError())
|
||||
printf("Error: %d at %zu\n", static_cast<int>(doc.GetParseError()), doc.GetErrorOffset());
|
||||
EXPECT_TRUE(static_cast<ParseResult>(doc));
|
||||
|
||||
EXPECT_TRUE(doc.IsObject());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("hello"));
|
||||
const ValueType& hello = doc["hello"];
|
||||
EXPECT_TRUE(hello.IsString());
|
||||
EXPECT_STREQ("world", hello.GetString());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("t"));
|
||||
const ValueType& t = doc["t"];
|
||||
EXPECT_TRUE(t.IsTrue());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("f"));
|
||||
const ValueType& f = doc["f"];
|
||||
EXPECT_TRUE(f.IsFalse());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("n"));
|
||||
const ValueType& n = doc["n"];
|
||||
EXPECT_TRUE(n.IsNull());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("i"));
|
||||
const ValueType& i = doc["i"];
|
||||
EXPECT_TRUE(i.IsNumber());
|
||||
EXPECT_EQ(123, i.GetInt());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("pi"));
|
||||
const ValueType& pi = doc["pi"];
|
||||
EXPECT_TRUE(pi.IsNumber());
|
||||
EXPECT_DOUBLE_EQ(3.1416, pi.GetDouble());
|
||||
|
||||
EXPECT_TRUE(doc.HasMember("a"));
|
||||
const ValueType& a = doc["a"];
|
||||
EXPECT_TRUE(a.IsArray());
|
||||
EXPECT_EQ(4u, a.Size());
|
||||
for (SizeType j = 0; j < 4; j++)
|
||||
EXPECT_EQ(j + 1, a[j].GetUint());
|
||||
}
|
||||
|
||||
template <typename Allocator, typename StackAllocator>
|
||||
void ParseTest() {
|
||||
typedef GenericDocument<UTF8<>, Allocator, StackAllocator> DocumentType;
|
||||
DocumentType doc;
|
||||
|
||||
const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
|
||||
|
||||
doc.Parse(json);
|
||||
ParseCheck(doc);
|
||||
|
||||
doc.SetNull();
|
||||
StringStream s(json);
|
||||
doc.template ParseStream<0>(s);
|
||||
ParseCheck(doc);
|
||||
|
||||
doc.SetNull();
|
||||
char *buffer = strdup(json);
|
||||
doc.ParseInsitu(buffer);
|
||||
ParseCheck(doc);
|
||||
free(buffer);
|
||||
|
||||
// Parse(const Ch*, size_t)
|
||||
size_t length = strlen(json);
|
||||
buffer = reinterpret_cast<char*>(malloc(length * 2));
|
||||
memcpy(buffer, json, length);
|
||||
memset(buffer + length, 'X', length);
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
std::string s2(buffer, length); // backup buffer
|
||||
#endif
|
||||
doc.SetNull();
|
||||
doc.Parse(buffer, length);
|
||||
free(buffer);
|
||||
ParseCheck(doc);
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
// Parse(std::string)
|
||||
doc.SetNull();
|
||||
doc.Parse(s2);
|
||||
ParseCheck(doc);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Document, Parse) {
|
||||
ParseTest<MemoryPoolAllocator<>, CrtAllocator>();
|
||||
ParseTest<MemoryPoolAllocator<>, MemoryPoolAllocator<> >();
|
||||
ParseTest<CrtAllocator, MemoryPoolAllocator<> >();
|
||||
ParseTest<CrtAllocator, CrtAllocator>();
|
||||
}
|
||||
|
||||
TEST(Document, UnchangedOnParseError) {
|
||||
Document doc;
|
||||
doc.SetArray().PushBack(0, doc.GetAllocator());
|
||||
|
||||
ParseResult err = doc.Parse("{]");
|
||||
EXPECT_TRUE(doc.HasParseError());
|
||||
EXPECT_EQ(err.Code(), doc.GetParseError());
|
||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
|
||||
EXPECT_TRUE(doc.IsArray());
|
||||
EXPECT_EQ(doc.Size(), 1u);
|
||||
|
||||
err = doc.Parse("{}");
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
EXPECT_FALSE(err.IsError());
|
||||
EXPECT_EQ(err.Code(), doc.GetParseError());
|
||||
EXPECT_EQ(err.Offset(), doc.GetErrorOffset());
|
||||
EXPECT_TRUE(doc.IsObject());
|
||||
EXPECT_EQ(doc.MemberCount(), 0u);
|
||||
}
|
||||
|
||||
static FILE* OpenEncodedFile(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;
|
||||
}
|
||||
|
||||
TEST(Document, Parse_Encoding) {
|
||||
const char* json = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
|
||||
|
||||
typedef GenericDocument<UTF16<> > DocumentType;
|
||||
DocumentType doc;
|
||||
|
||||
// Parse<unsigned, SourceEncoding>(const SourceEncoding::Ch*)
|
||||
// doc.Parse<kParseDefaultFlags, UTF8<> >(json);
|
||||
// EXPECT_FALSE(doc.HasParseError());
|
||||
// EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world"));
|
||||
|
||||
// Parse<unsigned, SourceEncoding>(const SourceEncoding::Ch*, size_t)
|
||||
size_t length = strlen(json);
|
||||
char* buffer = reinterpret_cast<char*>(malloc(length * 2));
|
||||
memcpy(buffer, json, length);
|
||||
memset(buffer + length, 'X', length);
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
std::string s2(buffer, length); // backup buffer
|
||||
#endif
|
||||
doc.SetNull();
|
||||
doc.Parse<kParseDefaultFlags, UTF8<> >(buffer, length);
|
||||
free(buffer);
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
if (doc.HasParseError())
|
||||
printf("Error: %d at %zu\n", static_cast<int>(doc.GetParseError()), doc.GetErrorOffset());
|
||||
EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world"));
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
// Parse<unsigned, SourceEncoding>(std::string)
|
||||
doc.SetNull();
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
doc.Parse<kParseDefaultFlags, UTF8<> >(s2.c_str()); // VS2010 or below cannot handle templated function overloading. Use const char* instead.
|
||||
#else
|
||||
doc.Parse<kParseDefaultFlags, UTF8<> >(s2);
|
||||
#endif
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
EXPECT_EQ(0, StrCmp(doc[L"hello"].GetString(), L"world"));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(Document, ParseStream_EncodedInputStream) {
|
||||
// UTF8 -> UTF16
|
||||
FILE* fp = OpenEncodedFile("utf8.json");
|
||||
char buffer[256];
|
||||
FileReadStream bis(fp, buffer, sizeof(buffer));
|
||||
EncodedInputStream<UTF8<>, FileReadStream> eis(bis);
|
||||
|
||||
GenericDocument<UTF16<> > d;
|
||||
d.ParseStream<0, UTF8<> >(eis);
|
||||
EXPECT_FALSE(d.HasParseError());
|
||||
|
||||
fclose(fp);
|
||||
|
||||
wchar_t expected[] = L"I can eat glass and it doesn't hurt me.";
|
||||
GenericValue<UTF16<> >& v = d[L"en"];
|
||||
EXPECT_TRUE(v.IsString());
|
||||
EXPECT_EQ(sizeof(expected) / sizeof(wchar_t) - 1, v.GetStringLength());
|
||||
EXPECT_EQ(0, StrCmp(expected, v.GetString()));
|
||||
|
||||
// UTF16 -> UTF8 in memory
|
||||
StringBuffer bos;
|
||||
typedef EncodedOutputStream<UTF8<>, StringBuffer> OutputStream;
|
||||
OutputStream eos(bos, false); // Not writing BOM
|
||||
{
|
||||
Writer<OutputStream, UTF16<>, UTF8<> > writer(eos);
|
||||
d.Accept(writer);
|
||||
}
|
||||
|
||||
// Condense the original file and compare.
|
||||
fp = OpenEncodedFile("utf8.json");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
Reader reader;
|
||||
StringBuffer bos2;
|
||||
Writer<StringBuffer> writer2(bos2);
|
||||
reader.Parse(is, writer2);
|
||||
fclose(fp);
|
||||
|
||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
||||
}
|
||||
|
||||
TEST(Document, ParseStream_AutoUTFInputStream) {
|
||||
// Any -> UTF8
|
||||
FILE* fp = OpenEncodedFile("utf32be.json");
|
||||
char buffer[256];
|
||||
FileReadStream bis(fp, buffer, sizeof(buffer));
|
||||
AutoUTFInputStream<unsigned, FileReadStream> eis(bis);
|
||||
|
||||
Document d;
|
||||
d.ParseStream<0, AutoUTF<unsigned> >(eis);
|
||||
EXPECT_FALSE(d.HasParseError());
|
||||
|
||||
fclose(fp);
|
||||
|
||||
char expected[] = "I can eat glass and it doesn't hurt me.";
|
||||
Value& v = d["en"];
|
||||
EXPECT_TRUE(v.IsString());
|
||||
EXPECT_EQ(sizeof(expected) - 1, v.GetStringLength());
|
||||
EXPECT_EQ(0, StrCmp(expected, v.GetString()));
|
||||
|
||||
// UTF8 -> UTF8 in memory
|
||||
StringBuffer bos;
|
||||
Writer<StringBuffer> writer(bos);
|
||||
d.Accept(writer);
|
||||
|
||||
// Condense the original file and compare.
|
||||
fp = OpenEncodedFile("utf8.json");
|
||||
FileReadStream is(fp, buffer, sizeof(buffer));
|
||||
Reader reader;
|
||||
StringBuffer bos2;
|
||||
Writer<StringBuffer> writer2(bos2);
|
||||
reader.Parse(is, writer2);
|
||||
fclose(fp);
|
||||
|
||||
EXPECT_EQ(bos.GetSize(), bos2.GetSize());
|
||||
EXPECT_EQ(0, memcmp(bos.GetString(), bos2.GetString(), bos2.GetSize()));
|
||||
}
|
||||
|
||||
TEST(Document, Swap) {
|
||||
Document d1;
|
||||
Document::AllocatorType& a = d1.GetAllocator();
|
||||
|
||||
d1.SetArray().PushBack(1, a).PushBack(2, a);
|
||||
|
||||
Value o;
|
||||
o.SetObject().AddMember("a", 1, a);
|
||||
|
||||
// Swap between Document and Value
|
||||
// d1.Swap(o); // doesn't compile
|
||||
o.Swap(d1);
|
||||
EXPECT_TRUE(d1.IsObject());
|
||||
EXPECT_TRUE(o.IsArray());
|
||||
|
||||
// Swap between Document and Document
|
||||
Document d2;
|
||||
d2.SetArray().PushBack(3, a);
|
||||
d1.Swap(d2);
|
||||
EXPECT_TRUE(d1.IsArray());
|
||||
EXPECT_TRUE(d2.IsObject());
|
||||
EXPECT_EQ(&d2.GetAllocator(), &a);
|
||||
|
||||
// reset value
|
||||
Value().Swap(d1);
|
||||
EXPECT_TRUE(d1.IsNull());
|
||||
|
||||
// reset document, including allocator
|
||||
Document().Swap(d2);
|
||||
EXPECT_TRUE(d2.IsNull());
|
||||
EXPECT_NE(&d2.GetAllocator(), &a);
|
||||
|
||||
// testing std::swap compatibility
|
||||
d1.SetBool(true);
|
||||
using std::swap;
|
||||
swap(d1, d2);
|
||||
EXPECT_TRUE(d1.IsNull());
|
||||
EXPECT_TRUE(d2.IsTrue());
|
||||
|
||||
swap(o, d2);
|
||||
EXPECT_TRUE(o.IsTrue());
|
||||
EXPECT_TRUE(d2.IsArray());
|
||||
}
|
||||
|
||||
|
||||
// This should be slow due to assignment in inner-loop.
|
||||
struct OutputStringStream : public std::ostringstream {
|
||||
typedef char Ch;
|
||||
|
||||
virtual ~OutputStringStream();
|
||||
|
||||
void Put(char c) {
|
||||
put(c);
|
||||
}
|
||||
void Flush() {}
|
||||
};
|
||||
|
||||
OutputStringStream::~OutputStringStream() {}
|
||||
|
||||
TEST(Document, AcceptWriter) {
|
||||
Document doc;
|
||||
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||
|
||||
OutputStringStream os;
|
||||
Writer<OutputStringStream> writer(os);
|
||||
doc.Accept(writer);
|
||||
|
||||
EXPECT_EQ("{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,4]}", os.str());
|
||||
}
|
||||
|
||||
TEST(Document, UserBuffer) {
|
||||
typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<> > DocumentType;
|
||||
char valueBuffer[4096];
|
||||
char parseBuffer[1024];
|
||||
MemoryPoolAllocator<> valueAllocator(valueBuffer, sizeof(valueBuffer));
|
||||
MemoryPoolAllocator<> parseAllocator(parseBuffer, sizeof(parseBuffer));
|
||||
DocumentType doc(&valueAllocator, sizeof(parseBuffer) / 2, &parseAllocator);
|
||||
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||
EXPECT_FALSE(doc.HasParseError());
|
||||
EXPECT_LE(valueAllocator.Size(), sizeof(valueBuffer));
|
||||
EXPECT_LE(parseAllocator.Size(), sizeof(parseBuffer));
|
||||
|
||||
// Cover MemoryPoolAllocator::Capacity()
|
||||
EXPECT_LE(valueAllocator.Size(), valueAllocator.Capacity());
|
||||
EXPECT_LE(parseAllocator.Size(), parseAllocator.Capacity());
|
||||
}
|
||||
|
||||
// Issue 226: Value of string type should not point to NULL
|
||||
TEST(Document, AssertAcceptInvalidNameType) {
|
||||
Document doc;
|
||||
doc.SetObject();
|
||||
doc.AddMember("a", 0, doc.GetAllocator());
|
||||
doc.FindMember("a")->name.SetNull(); // Change name to non-string type.
|
||||
|
||||
OutputStringStream os;
|
||||
Writer<OutputStringStream> writer(os);
|
||||
ASSERT_THROW(doc.Accept(writer), AssertException);
|
||||
}
|
||||
|
||||
// Issue 44: SetStringRaw doesn't work with wchar_t
|
||||
TEST(Document, UTF16_Document) {
|
||||
GenericDocument< UTF16<> > json;
|
||||
json.Parse<kParseValidateEncodingFlag>(L"[{\"created_at\":\"Wed Oct 30 17:13:20 +0000 2012\"}]");
|
||||
|
||||
ASSERT_TRUE(json.IsArray());
|
||||
GenericValue< UTF16<> >& v = json[0];
|
||||
ASSERT_TRUE(v.IsObject());
|
||||
|
||||
GenericValue< UTF16<> >& s = v[L"created_at"];
|
||||
ASSERT_TRUE(s.IsString());
|
||||
|
||||
EXPECT_EQ(0, memcmp(L"Wed Oct 30 17:13:20 +0000 2012", s.GetString(), (s.GetStringLength() + 1) * sizeof(wchar_t)));
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
|
||||
#if 0 // Many old compiler does not support these. Turn it off temporaily.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
TEST(Document, Traits) {
|
||||
static_assert(std::is_constructible<Document>::value, "");
|
||||
static_assert(std::is_default_constructible<Document>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(!std::is_copy_constructible<Document>::value, "");
|
||||
#endif
|
||||
static_assert(std::is_move_constructible<Document>::value, "");
|
||||
|
||||
static_assert(!std::is_nothrow_constructible<Document>::value, "");
|
||||
static_assert(!std::is_nothrow_default_constructible<Document>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(!std::is_nothrow_copy_constructible<Document>::value, "");
|
||||
static_assert(std::is_nothrow_move_constructible<Document>::value, "");
|
||||
#endif
|
||||
|
||||
static_assert(std::is_assignable<Document,Document>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(!std::is_copy_assignable<Document>::value, "");
|
||||
#endif
|
||||
static_assert(std::is_move_assignable<Document>::value, "");
|
||||
|
||||
#ifndef _MSC_VER
|
||||
static_assert(std::is_nothrow_assignable<Document, Document>::value, "");
|
||||
#endif
|
||||
static_assert(!std::is_nothrow_copy_assignable<Document>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(std::is_nothrow_move_assignable<Document>::value, "");
|
||||
#endif
|
||||
|
||||
static_assert( std::is_destructible<Document>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(std::is_nothrow_destructible<Document>::value, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename Allocator>
|
||||
struct DocumentMove: public ::testing::Test {
|
||||
};
|
||||
|
||||
typedef ::testing::Types< CrtAllocator, MemoryPoolAllocator<> > MoveAllocatorTypes;
|
||||
TYPED_TEST_CASE(DocumentMove, MoveAllocatorTypes);
|
||||
|
||||
TYPED_TEST(DocumentMove, MoveConstructor) {
|
||||
typedef TypeParam Allocator;
|
||||
typedef GenericDocument<UTF8<>, Allocator> D;
|
||||
Allocator allocator;
|
||||
|
||||
D a(&allocator);
|
||||
a.Parse("[\"one\", \"two\", \"three\"]");
|
||||
EXPECT_FALSE(a.HasParseError());
|
||||
EXPECT_TRUE(a.IsArray());
|
||||
EXPECT_EQ(3u, a.Size());
|
||||
EXPECT_EQ(&a.GetAllocator(), &allocator);
|
||||
|
||||
// Document b(a); // does not compile (!is_copy_constructible)
|
||||
D b(std::move(a));
|
||||
EXPECT_TRUE(a.IsNull());
|
||||
EXPECT_TRUE(b.IsArray());
|
||||
EXPECT_EQ(3u, b.Size());
|
||||
EXPECT_THROW(a.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
||||
|
||||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
||||
EXPECT_FALSE(b.HasParseError());
|
||||
EXPECT_TRUE(b.IsObject());
|
||||
EXPECT_EQ(2u, b.MemberCount());
|
||||
|
||||
// Document c = a; // does not compile (!is_copy_constructible)
|
||||
D c = std::move(b);
|
||||
EXPECT_TRUE(b.IsNull());
|
||||
EXPECT_TRUE(c.IsObject());
|
||||
EXPECT_EQ(2u, c.MemberCount());
|
||||
EXPECT_THROW(b.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
||||
}
|
||||
|
||||
TYPED_TEST(DocumentMove, MoveConstructorParseError) {
|
||||
typedef TypeParam Allocator;
|
||||
typedef GenericDocument<UTF8<>, Allocator> D;
|
||||
|
||||
ParseResult noError;
|
||||
D a;
|
||||
a.Parse("{ 4 = 4]");
|
||||
ParseResult error(a.GetParseError(), a.GetErrorOffset());
|
||||
EXPECT_TRUE(a.HasParseError());
|
||||
EXPECT_NE(error.Code(), noError.Code());
|
||||
EXPECT_NE(error.Offset(), noError.Offset());
|
||||
|
||||
D b(std::move(a));
|
||||
EXPECT_FALSE(a.HasParseError());
|
||||
EXPECT_TRUE(b.HasParseError());
|
||||
EXPECT_EQ(a.GetParseError(), noError.Code());
|
||||
EXPECT_EQ(b.GetParseError(), error.Code());
|
||||
EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
|
||||
EXPECT_EQ(b.GetErrorOffset(), error.Offset());
|
||||
|
||||
D c(std::move(b));
|
||||
EXPECT_FALSE(b.HasParseError());
|
||||
EXPECT_TRUE(c.HasParseError());
|
||||
EXPECT_EQ(b.GetParseError(), noError.Code());
|
||||
EXPECT_EQ(c.GetParseError(), error.Code());
|
||||
EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
|
||||
EXPECT_EQ(c.GetErrorOffset(), error.Offset());
|
||||
}
|
||||
|
||||
// This test does not properly use parsing, just for testing.
|
||||
// It must call ClearStack() explicitly to prevent memory leak.
|
||||
// But here we cannot as ClearStack() is private.
|
||||
#if 0
|
||||
TYPED_TEST(DocumentMove, MoveConstructorStack) {
|
||||
typedef TypeParam Allocator;
|
||||
typedef UTF8<> Encoding;
|
||||
typedef GenericDocument<Encoding, Allocator> Document;
|
||||
|
||||
Document a;
|
||||
size_t defaultCapacity = a.GetStackCapacity();
|
||||
|
||||
// Trick Document into getting GetStackCapacity() to return non-zero
|
||||
typedef GenericReader<Encoding, Encoding, Allocator> Reader;
|
||||
Reader reader(&a.GetAllocator());
|
||||
GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
|
||||
reader.template Parse<kParseDefaultFlags>(is, a);
|
||||
size_t capacity = a.GetStackCapacity();
|
||||
EXPECT_GT(capacity, 0u);
|
||||
|
||||
Document b(std::move(a));
|
||||
EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
|
||||
EXPECT_EQ(b.GetStackCapacity(), capacity);
|
||||
|
||||
Document c = std::move(b);
|
||||
EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
|
||||
EXPECT_EQ(c.GetStackCapacity(), capacity);
|
||||
}
|
||||
#endif
|
||||
|
||||
TYPED_TEST(DocumentMove, MoveAssignment) {
|
||||
typedef TypeParam Allocator;
|
||||
typedef GenericDocument<UTF8<>, Allocator> D;
|
||||
Allocator allocator;
|
||||
|
||||
D a(&allocator);
|
||||
a.Parse("[\"one\", \"two\", \"three\"]");
|
||||
EXPECT_FALSE(a.HasParseError());
|
||||
EXPECT_TRUE(a.IsArray());
|
||||
EXPECT_EQ(3u, a.Size());
|
||||
EXPECT_EQ(&a.GetAllocator(), &allocator);
|
||||
|
||||
// Document b; b = a; // does not compile (!is_copy_assignable)
|
||||
D b;
|
||||
b = std::move(a);
|
||||
EXPECT_TRUE(a.IsNull());
|
||||
EXPECT_TRUE(b.IsArray());
|
||||
EXPECT_EQ(3u, b.Size());
|
||||
EXPECT_THROW(a.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&b.GetAllocator(), &allocator);
|
||||
|
||||
b.Parse("{\"Foo\": \"Bar\", \"Baz\": 42}");
|
||||
EXPECT_FALSE(b.HasParseError());
|
||||
EXPECT_TRUE(b.IsObject());
|
||||
EXPECT_EQ(2u, b.MemberCount());
|
||||
|
||||
// Document c; c = a; // does not compile (see static_assert)
|
||||
D c;
|
||||
c = std::move(b);
|
||||
EXPECT_TRUE(b.IsNull());
|
||||
EXPECT_TRUE(c.IsObject());
|
||||
EXPECT_EQ(2u, c.MemberCount());
|
||||
EXPECT_THROW(b.GetAllocator(), AssertException);
|
||||
EXPECT_EQ(&c.GetAllocator(), &allocator);
|
||||
}
|
||||
|
||||
TYPED_TEST(DocumentMove, MoveAssignmentParseError) {
|
||||
typedef TypeParam Allocator;
|
||||
typedef GenericDocument<UTF8<>, Allocator> D;
|
||||
|
||||
ParseResult noError;
|
||||
D a;
|
||||
a.Parse("{ 4 = 4]");
|
||||
ParseResult error(a.GetParseError(), a.GetErrorOffset());
|
||||
EXPECT_TRUE(a.HasParseError());
|
||||
EXPECT_NE(error.Code(), noError.Code());
|
||||
EXPECT_NE(error.Offset(), noError.Offset());
|
||||
|
||||
D b;
|
||||
b = std::move(a);
|
||||
EXPECT_FALSE(a.HasParseError());
|
||||
EXPECT_TRUE(b.HasParseError());
|
||||
EXPECT_EQ(a.GetParseError(), noError.Code());
|
||||
EXPECT_EQ(b.GetParseError(), error.Code());
|
||||
EXPECT_EQ(a.GetErrorOffset(), noError.Offset());
|
||||
EXPECT_EQ(b.GetErrorOffset(), error.Offset());
|
||||
|
||||
D c;
|
||||
c = std::move(b);
|
||||
EXPECT_FALSE(b.HasParseError());
|
||||
EXPECT_TRUE(c.HasParseError());
|
||||
EXPECT_EQ(b.GetParseError(), noError.Code());
|
||||
EXPECT_EQ(c.GetParseError(), error.Code());
|
||||
EXPECT_EQ(b.GetErrorOffset(), noError.Offset());
|
||||
EXPECT_EQ(c.GetErrorOffset(), error.Offset());
|
||||
}
|
||||
|
||||
// This test does not properly use parsing, just for testing.
|
||||
// It must call ClearStack() explicitly to prevent memory leak.
|
||||
// But here we cannot as ClearStack() is private.
|
||||
#if 0
|
||||
TYPED_TEST(DocumentMove, MoveAssignmentStack) {
|
||||
typedef TypeParam Allocator;
|
||||
typedef UTF8<> Encoding;
|
||||
typedef GenericDocument<Encoding, Allocator> D;
|
||||
|
||||
D a;
|
||||
size_t defaultCapacity = a.GetStackCapacity();
|
||||
|
||||
// Trick Document into getting GetStackCapacity() to return non-zero
|
||||
typedef GenericReader<Encoding, Encoding, Allocator> Reader;
|
||||
Reader reader(&a.GetAllocator());
|
||||
GenericStringStream<Encoding> is("[\"one\", \"two\", \"three\"]");
|
||||
reader.template Parse<kParseDefaultFlags>(is, a);
|
||||
size_t capacity = a.GetStackCapacity();
|
||||
EXPECT_GT(capacity, 0u);
|
||||
|
||||
D b;
|
||||
b = std::move(a);
|
||||
EXPECT_EQ(a.GetStackCapacity(), defaultCapacity);
|
||||
EXPECT_EQ(b.GetStackCapacity(), capacity);
|
||||
|
||||
D c;
|
||||
c = std::move(b);
|
||||
EXPECT_EQ(b.GetStackCapacity(), defaultCapacity);
|
||||
EXPECT_EQ(c.GetStackCapacity(), capacity);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
|
||||
// Issue 22: Memory corruption via operator=
|
||||
// Fixed by making unimplemented assignment operator private.
|
||||
//TEST(Document, Assignment) {
|
||||
// Document d1;
|
||||
// Document d2;
|
||||
// d1 = d2;
|
||||
//}
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
@ -1,98 +0,0 @@
|
||||
// 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/internal/dtoa.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(type-limits)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson::internal;
|
||||
|
||||
TEST(dtoa, normal) {
|
||||
char buffer[30];
|
||||
|
||||
#define TEST_DTOA(d, a)\
|
||||
*dtoa(d, buffer) = '\0';\
|
||||
EXPECT_STREQ(a, buffer)
|
||||
|
||||
TEST_DTOA(0.0, "0.0");
|
||||
TEST_DTOA(-0.0, "-0.0");
|
||||
TEST_DTOA(1.0, "1.0");
|
||||
TEST_DTOA(-1.0, "-1.0");
|
||||
TEST_DTOA(1.2345, "1.2345");
|
||||
TEST_DTOA(1.2345678, "1.2345678");
|
||||
TEST_DTOA(0.123456789012, "0.123456789012");
|
||||
TEST_DTOA(1234567.8, "1234567.8");
|
||||
TEST_DTOA(-79.39773355813419, "-79.39773355813419");
|
||||
TEST_DTOA(0.000001, "0.000001");
|
||||
TEST_DTOA(0.0000001, "1e-7");
|
||||
TEST_DTOA(1e30, "1e30");
|
||||
TEST_DTOA(1.234567890123456e30, "1.234567890123456e30");
|
||||
TEST_DTOA(5e-324, "5e-324"); // Min subnormal positive double
|
||||
TEST_DTOA(2.225073858507201e-308, "2.225073858507201e-308"); // Max subnormal positive double
|
||||
TEST_DTOA(2.2250738585072014e-308, "2.2250738585072014e-308"); // Min normal positive double
|
||||
TEST_DTOA(1.7976931348623157e308, "1.7976931348623157e308"); // Max double
|
||||
|
||||
#undef TEST_DTOA
|
||||
}
|
||||
|
||||
TEST(dtoa, maxDecimalPlaces) {
|
||||
char buffer[30];
|
||||
|
||||
#define TEST_DTOA(m, d, a)\
|
||||
*dtoa(d, buffer, m) = '\0';\
|
||||
EXPECT_STREQ(a, buffer)
|
||||
|
||||
TEST_DTOA(3, 0.0, "0.0");
|
||||
TEST_DTOA(1, 0.0, "0.0");
|
||||
TEST_DTOA(3, -0.0, "-0.0");
|
||||
TEST_DTOA(3, 1.0, "1.0");
|
||||
TEST_DTOA(3, -1.0, "-1.0");
|
||||
TEST_DTOA(3, 1.2345, "1.234");
|
||||
TEST_DTOA(2, 1.2345, "1.23");
|
||||
TEST_DTOA(1, 1.2345, "1.2");
|
||||
TEST_DTOA(3, 1.2345678, "1.234");
|
||||
TEST_DTOA(3, 1.0001, "1.0");
|
||||
TEST_DTOA(2, 1.0001, "1.0");
|
||||
TEST_DTOA(1, 1.0001, "1.0");
|
||||
TEST_DTOA(3, 0.123456789012, "0.123");
|
||||
TEST_DTOA(2, 0.123456789012, "0.12");
|
||||
TEST_DTOA(1, 0.123456789012, "0.1");
|
||||
TEST_DTOA(4, 0.0001, "0.0001");
|
||||
TEST_DTOA(3, 0.0001, "0.0");
|
||||
TEST_DTOA(2, 0.0001, "0.0");
|
||||
TEST_DTOA(1, 0.0001, "0.0");
|
||||
TEST_DTOA(3, 1234567.8, "1234567.8");
|
||||
TEST_DTOA(3, 1e30, "1e30");
|
||||
TEST_DTOA(3, 5e-324, "0.0"); // Min subnormal positive double
|
||||
TEST_DTOA(3, 2.225073858507201e-308, "0.0"); // Max subnormal positive double
|
||||
TEST_DTOA(3, 2.2250738585072014e-308, "0.0"); // Min normal positive double
|
||||
TEST_DTOA(3, 1.7976931348623157e308, "1.7976931348623157e308"); // Max double
|
||||
TEST_DTOA(5, -0.14000000000000001, "-0.14");
|
||||
TEST_DTOA(4, -0.14000000000000001, "-0.14");
|
||||
TEST_DTOA(3, -0.14000000000000001, "-0.14");
|
||||
TEST_DTOA(3, -0.10000000000000001, "-0.1");
|
||||
TEST_DTOA(2, -0.10000000000000001, "-0.1");
|
||||
TEST_DTOA(1, -0.10000000000000001, "-0.1");
|
||||
|
||||
#undef TEST_DTOA
|
||||
}
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
@ -1,313 +0,0 @@
|
||||
// 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,451 +0,0 @@
|
||||
// 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(EncodingsTest, ASCII) {
|
||||
StringBuffer os, os2;
|
||||
for (unsigned codepoint = 0; codepoint < 128; codepoint++) {
|
||||
os.Clear();
|
||||
ASCII<>::Encode(os, codepoint);
|
||||
const ASCII<>::Ch* encodedStr = os.GetString();
|
||||
{
|
||||
StringStream is(encodedStr);
|
||||
unsigned decodedCodepoint;
|
||||
bool result = ASCII<>::Decode(is, &decodedCodepoint);
|
||||
if (!result || codepoint != decodedCodepoint)
|
||||
std::cout << std::hex << codepoint << " " << decodedCodepoint << std::endl;
|
||||
}
|
||||
|
||||
// Validate
|
||||
{
|
||||
StringStream is(encodedStr);
|
||||
os2.Clear();
|
||||
bool result = ASCII<>::Validate(is, os2);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(0, StrCmp(encodedStr, os2.GetString()));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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,181 +0,0 @@
|
||||
// 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/istreamwrapper.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
template <typename StringStreamType>
|
||||
static void TestStringStream() {
|
||||
typedef typename StringStreamType::char_type Ch;
|
||||
|
||||
{
|
||||
StringStreamType iss;
|
||||
BasicIStreamWrapper<StringStreamType> is(iss);
|
||||
EXPECT_EQ(0, is.Tell());
|
||||
if (sizeof(Ch) == 1) {
|
||||
EXPECT_EQ(0, is.Peek4());
|
||||
EXPECT_EQ(0, is.Tell());
|
||||
}
|
||||
EXPECT_EQ(0, is.Peek());
|
||||
EXPECT_EQ(0, is.Take());
|
||||
EXPECT_EQ(0, is.Tell());
|
||||
}
|
||||
|
||||
{
|
||||
Ch s[] = { 'A', 'B', 'C', '\0' };
|
||||
StringStreamType iss(s);
|
||||
BasicIStreamWrapper<StringStreamType> is(iss);
|
||||
EXPECT_EQ(0, is.Tell());
|
||||
if (sizeof(Ch) == 1) {
|
||||
EXPECT_EQ(0, is.Peek4()); // less than 4 bytes
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
EXPECT_EQ(static_cast<size_t>(i), is.Tell());
|
||||
EXPECT_EQ('A' + i, is.Peek());
|
||||
EXPECT_EQ('A' + i, is.Peek());
|
||||
EXPECT_EQ('A' + i, is.Take());
|
||||
}
|
||||
EXPECT_EQ(3, is.Tell());
|
||||
EXPECT_EQ(0, is.Peek());
|
||||
EXPECT_EQ(0, is.Take());
|
||||
}
|
||||
|
||||
{
|
||||
Ch s[] = { 'A', 'B', 'C', 'D', 'E', '\0' };
|
||||
StringStreamType iss(s);
|
||||
BasicIStreamWrapper<StringStreamType> is(iss);
|
||||
if (sizeof(Ch) == 1) {
|
||||
const Ch* c = is.Peek4();
|
||||
for (int i = 0; i < 4; i++)
|
||||
EXPECT_EQ('A' + i, c[i]);
|
||||
EXPECT_EQ(0, is.Tell());
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(static_cast<size_t>(i), is.Tell());
|
||||
EXPECT_EQ('A' + i, is.Peek());
|
||||
EXPECT_EQ('A' + i, is.Peek());
|
||||
EXPECT_EQ('A' + i, is.Take());
|
||||
}
|
||||
EXPECT_EQ(5, is.Tell());
|
||||
EXPECT_EQ(0, is.Peek());
|
||||
EXPECT_EQ(0, is.Take());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(IStreamWrapper, istringstream) {
|
||||
TestStringStream<istringstream>();
|
||||
}
|
||||
|
||||
TEST(IStreamWrapper, stringstream) {
|
||||
TestStringStream<stringstream>();
|
||||
}
|
||||
|
||||
TEST(IStreamWrapper, wistringstream) {
|
||||
TestStringStream<wistringstream>();
|
||||
}
|
||||
|
||||
TEST(IStreamWrapper, wstringstream) {
|
||||
TestStringStream<wstringstream>();
|
||||
}
|
||||
|
||||
template <typename FileStreamType>
|
||||
static bool Open(FileStreamType& fs, 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);
|
||||
fs.open(buffer, ios_base::in | ios_base::binary);
|
||||
if (fs.is_open())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST(IStreamWrapper, ifstream) {
|
||||
ifstream ifs;
|
||||
ASSERT_TRUE(Open(ifs, "utf8bom.json"));
|
||||
IStreamWrapper isw(ifs);
|
||||
EncodedInputStream<UTF8<>, IStreamWrapper> eis(isw);
|
||||
Document d;
|
||||
EXPECT_TRUE(!d.ParseStream(eis).HasParseError());
|
||||
EXPECT_TRUE(d.IsObject());
|
||||
EXPECT_EQ(5, d.MemberCount());
|
||||
}
|
||||
|
||||
TEST(IStreamWrapper, fstream) {
|
||||
fstream fs;
|
||||
ASSERT_TRUE(Open(fs, "utf8bom.json"));
|
||||
IStreamWrapper isw(fs);
|
||||
EncodedInputStream<UTF8<>, IStreamWrapper> eis(isw);
|
||||
Document d;
|
||||
EXPECT_TRUE(!d.ParseStream(eis).HasParseError());
|
||||
EXPECT_TRUE(d.IsObject());
|
||||
EXPECT_EQ(5, d.MemberCount());
|
||||
}
|
||||
|
||||
// wifstream/wfstream only works on C++11 with codecvt_utf16
|
||||
// But many C++11 library still not have it.
|
||||
#if 0
|
||||
#include <codecvt>
|
||||
|
||||
TEST(IStreamWrapper, wifstream) {
|
||||
wifstream ifs;
|
||||
ASSERT_TRUE(Open(ifs, "utf16bebom.json"));
|
||||
ifs.imbue(std::locale(ifs.getloc(),
|
||||
new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
|
||||
WIStreamWrapper isw(ifs);
|
||||
GenericDocument<UTF16<> > d;
|
||||
d.ParseStream<kParseDefaultFlags, UTF16<>, WIStreamWrapper>(isw);
|
||||
EXPECT_TRUE(!d.HasParseError());
|
||||
EXPECT_TRUE(d.IsObject());
|
||||
EXPECT_EQ(5, d.MemberCount());
|
||||
}
|
||||
|
||||
TEST(IStreamWrapper, wfstream) {
|
||||
wfstream fs;
|
||||
ASSERT_TRUE(Open(fs, "utf16bebom.json"));
|
||||
fs.imbue(std::locale(fs.getloc(),
|
||||
new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
|
||||
WIStreamWrapper isw(fs);
|
||||
GenericDocument<UTF16<> > d;
|
||||
d.ParseStream<kParseDefaultFlags, UTF16<>, WIStreamWrapper>(isw);
|
||||
EXPECT_TRUE(!d.HasParseError());
|
||||
EXPECT_TRUE(d.IsObject());
|
||||
EXPECT_EQ(5, d.MemberCount());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
@ -1,160 +0,0 @@
|
||||
// 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/internal/itoa.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(type-limits)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson::internal;
|
||||
|
||||
template <typename T>
|
||||
struct Traits {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<uint32_t> {
|
||||
enum { kBufferSize = 11 };
|
||||
enum { kMaxDigit = 10 };
|
||||
static uint32_t Negate(uint32_t x) { return x; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<int32_t> {
|
||||
enum { kBufferSize = 12 };
|
||||
enum { kMaxDigit = 10 };
|
||||
static int32_t Negate(int32_t x) { return -x; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<uint64_t> {
|
||||
enum { kBufferSize = 21 };
|
||||
enum { kMaxDigit = 20 };
|
||||
static uint64_t Negate(uint64_t x) { return x; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Traits<int64_t> {
|
||||
enum { kBufferSize = 22 };
|
||||
enum { kMaxDigit = 20 };
|
||||
static int64_t Negate(int64_t x) { return -x; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static void VerifyValue(T value, void(*f)(T, char*), char* (*g)(T, char*)) {
|
||||
char buffer1[Traits<T>::kBufferSize];
|
||||
char buffer2[Traits<T>::kBufferSize];
|
||||
|
||||
f(value, buffer1);
|
||||
*g(value, buffer2) = '\0';
|
||||
|
||||
|
||||
EXPECT_STREQ(buffer1, buffer2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void Verify(void(*f)(T, char*), char* (*g)(T, char*)) {
|
||||
// Boundary cases
|
||||
VerifyValue<T>(0, f, g);
|
||||
VerifyValue<T>(std::numeric_limits<T>::min(), f, g);
|
||||
VerifyValue<T>(std::numeric_limits<T>::max(), f, g);
|
||||
|
||||
// 2^n - 1, 2^n, 10^n - 1, 10^n until overflow
|
||||
for (uint32_t power = 2; power <= 10; power += 8) {
|
||||
T i = 1, last;
|
||||
do {
|
||||
VerifyValue<T>(i - 1, f, g);
|
||||
VerifyValue<T>(i, f, g);
|
||||
if (std::numeric_limits<T>::min() < 0) {
|
||||
VerifyValue<T>(Traits<T>::Negate(i), f, g);
|
||||
VerifyValue<T>(Traits<T>::Negate(i + 1), f, g);
|
||||
}
|
||||
last = i;
|
||||
if (i > static_cast<T>(std::numeric_limits<T>::max() / static_cast<T>(power)))
|
||||
break;
|
||||
i *= power;
|
||||
} while (last < i);
|
||||
}
|
||||
}
|
||||
|
||||
static void u32toa_naive(uint32_t value, char* buffer) {
|
||||
char temp[10];
|
||||
char *p = temp;
|
||||
do {
|
||||
*p++ = static_cast<char>(char(value % 10) + '0');
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
do {
|
||||
*buffer++ = *--p;
|
||||
} while (p != temp);
|
||||
|
||||
*buffer = '\0';
|
||||
}
|
||||
|
||||
static void i32toa_naive(int32_t value, char* buffer) {
|
||||
uint32_t u = static_cast<uint32_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
u32toa_naive(u, buffer);
|
||||
}
|
||||
|
||||
static void u64toa_naive(uint64_t value, char* buffer) {
|
||||
char temp[20];
|
||||
char *p = temp;
|
||||
do {
|
||||
*p++ = static_cast<char>(char(value % 10) + '0');
|
||||
value /= 10;
|
||||
} while (value > 0);
|
||||
|
||||
do {
|
||||
*buffer++ = *--p;
|
||||
} while (p != temp);
|
||||
|
||||
*buffer = '\0';
|
||||
}
|
||||
|
||||
static void i64toa_naive(int64_t value, char* buffer) {
|
||||
uint64_t u = static_cast<uint64_t>(value);
|
||||
if (value < 0) {
|
||||
*buffer++ = '-';
|
||||
u = ~u + 1;
|
||||
}
|
||||
u64toa_naive(u, buffer);
|
||||
}
|
||||
|
||||
TEST(itoa, u32toa) {
|
||||
Verify(u32toa_naive, u32toa);
|
||||
}
|
||||
|
||||
TEST(itoa, i32toa) {
|
||||
Verify(i32toa_naive, i32toa);
|
||||
}
|
||||
|
||||
TEST(itoa, u64toa) {
|
||||
Verify(u64toa_naive, u64toa);
|
||||
}
|
||||
|
||||
TEST(itoa, i64toa) {
|
||||
Verify(i64toa_naive, i64toa);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
@ -1,99 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
// 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,91 +0,0 @@
|
||||
// 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/ostreamwrapper.h"
|
||||
#include "rapidjson/encodedstream.h"
|
||||
#include "rapidjson/document.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
template <typename StringStreamType>
|
||||
static void TestStringStream() {
|
||||
typedef typename StringStreamType::char_type Ch;
|
||||
|
||||
Ch s[] = { 'A', 'B', 'C', '\0' };
|
||||
StringStreamType oss(s);
|
||||
BasicOStreamWrapper<StringStreamType> os(oss);
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
os.Put(s[i]);
|
||||
os.Flush();
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
EXPECT_EQ(s[i], oss.str()[i]);
|
||||
}
|
||||
|
||||
TEST(OStreamWrapper, ostringstream) {
|
||||
TestStringStream<ostringstream>();
|
||||
}
|
||||
|
||||
TEST(OStreamWrapper, stringstream) {
|
||||
TestStringStream<stringstream>();
|
||||
}
|
||||
|
||||
TEST(OStreamWrapper, wostringstream) {
|
||||
TestStringStream<wostringstream>();
|
||||
}
|
||||
|
||||
TEST(OStreamWrapper, wstringstream) {
|
||||
TestStringStream<wstringstream>();
|
||||
}
|
||||
|
||||
TEST(OStreamWrapper, cout) {
|
||||
OStreamWrapper os(cout);
|
||||
const char* s = "Hello World!\n";
|
||||
while (*s)
|
||||
os.Put(*s++);
|
||||
os.Flush();
|
||||
}
|
||||
|
||||
template <typename FileStreamType>
|
||||
static void TestFileStream() {
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
fclose(fp);
|
||||
|
||||
const char* s = "Hello World!\n";
|
||||
{
|
||||
ofstream ofs(filename, ios::out | ios::binary);
|
||||
BasicOStreamWrapper<ofstream> osw(ofs);
|
||||
for (const char* p = s; *p; p++)
|
||||
osw.Put(*p);
|
||||
osw.Flush();
|
||||
}
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
for (const char* p = s; *p; p++)
|
||||
EXPECT_EQ(*p, static_cast<char>(fgetc(fp)));
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
TEST(OStreamWrapper, ofstream) {
|
||||
TestFileStream<ofstream>();
|
||||
}
|
||||
|
||||
TEST(OStreamWrapper, fstream) {
|
||||
TestFileStream<fstream>();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,203 +0,0 @@
|
||||
// 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/reader.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/filewritestream.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
static const char kJson[] = "{\"hello\":\"world\",\"t\":true,\"f\":false,\"n\":null,\"i\":123,\"pi\":3.1416,\"a\":[1,2,3,-1],\"u64\":1234567890123456789,\"i64\":-1234567890123456789}";
|
||||
static const char kPrettyJson[] =
|
||||
"{\n"
|
||||
" \"hello\": \"world\",\n"
|
||||
" \"t\": true,\n"
|
||||
" \"f\": false,\n"
|
||||
" \"n\": null,\n"
|
||||
" \"i\": 123,\n"
|
||||
" \"pi\": 3.1416,\n"
|
||||
" \"a\": [\n"
|
||||
" 1,\n"
|
||||
" 2,\n"
|
||||
" 3,\n"
|
||||
" -1\n"
|
||||
" ],\n"
|
||||
" \"u64\": 1234567890123456789,\n"
|
||||
" \"i64\": -1234567890123456789\n"
|
||||
"}";
|
||||
|
||||
static const char kPrettyJson_FormatOptions_SLA[] =
|
||||
"{\n"
|
||||
" \"hello\": \"world\",\n"
|
||||
" \"t\": true,\n"
|
||||
" \"f\": false,\n"
|
||||
" \"n\": null,\n"
|
||||
" \"i\": 123,\n"
|
||||
" \"pi\": 3.1416,\n"
|
||||
" \"a\": [1, 2, 3, -1],\n"
|
||||
" \"u64\": 1234567890123456789,\n"
|
||||
" \"i64\": -1234567890123456789\n"
|
||||
"}";
|
||||
|
||||
TEST(PrettyWriter, Basic) {
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
Reader reader;
|
||||
StringStream s(kJson);
|
||||
reader.Parse(s, writer);
|
||||
EXPECT_STREQ(kPrettyJson, buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, FormatOptions) {
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
writer.SetFormatOptions(kFormatSingleLineArray);
|
||||
Reader reader;
|
||||
StringStream s(kJson);
|
||||
reader.Parse(s, writer);
|
||||
EXPECT_STREQ(kPrettyJson_FormatOptions_SLA, buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, SetIndent) {
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
writer.SetIndent('\t', 1);
|
||||
Reader reader;
|
||||
StringStream s(kJson);
|
||||
reader.Parse(s, writer);
|
||||
EXPECT_STREQ(
|
||||
"{\n"
|
||||
"\t\"hello\": \"world\",\n"
|
||||
"\t\"t\": true,\n"
|
||||
"\t\"f\": false,\n"
|
||||
"\t\"n\": null,\n"
|
||||
"\t\"i\": 123,\n"
|
||||
"\t\"pi\": 3.1416,\n"
|
||||
"\t\"a\": [\n"
|
||||
"\t\t1,\n"
|
||||
"\t\t2,\n"
|
||||
"\t\t3,\n"
|
||||
"\t\t-1\n"
|
||||
"\t],\n"
|
||||
"\t\"u64\": 1234567890123456789,\n"
|
||||
"\t\"i64\": -1234567890123456789\n"
|
||||
"}",
|
||||
buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, String) {
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
EXPECT_TRUE(writer.StartArray());
|
||||
EXPECT_TRUE(writer.String("Hello\n"));
|
||||
EXPECT_TRUE(writer.EndArray());
|
||||
EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString());
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_STDSTRING
|
||||
TEST(PrettyWriter, String_STDSTRING) {
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
EXPECT_TRUE(writer.StartArray());
|
||||
EXPECT_TRUE(writer.String(std::string("Hello\n")));
|
||||
EXPECT_TRUE(writer.EndArray());
|
||||
EXPECT_STREQ("[\n \"Hello\\n\"\n]", buffer.GetString());
|
||||
}
|
||||
#endif
|
||||
|
||||
#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_;
|
||||
};
|
||||
|
||||
// For covering PutN() generic version
|
||||
TEST(PrettyWriter, OStreamWrapper) {
|
||||
StringStream s(kJson);
|
||||
|
||||
std::stringstream ss;
|
||||
OStreamWrapper os(ss);
|
||||
|
||||
PrettyWriter<OStreamWrapper> writer(os);
|
||||
|
||||
Reader reader;
|
||||
reader.Parse(s, writer);
|
||||
|
||||
std::string actual = ss.str();
|
||||
EXPECT_STREQ(kPrettyJson, actual.c_str());
|
||||
}
|
||||
|
||||
// For covering FileWriteStream::PutN()
|
||||
TEST(PrettyWriter, FileWriteStream) {
|
||||
char filename[L_tmpnam];
|
||||
FILE* fp = TempFile(filename);
|
||||
char buffer[16];
|
||||
FileWriteStream os(fp, buffer, sizeof(buffer));
|
||||
PrettyWriter<FileWriteStream> writer(os);
|
||||
Reader reader;
|
||||
StringStream s(kJson);
|
||||
reader.Parse(s, writer);
|
||||
fclose(fp);
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t size = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
char* json = static_cast<char*>(malloc(size + 1));
|
||||
size_t readLength = fread(json, 1, size, fp);
|
||||
json[readLength] = '\0';
|
||||
fclose(fp);
|
||||
remove(filename);
|
||||
EXPECT_STREQ(kPrettyJson, json);
|
||||
free(json);
|
||||
}
|
||||
|
||||
TEST(PrettyWriter, RawValue) {
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<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(
|
||||
"{\n"
|
||||
" \"a\": 1,\n"
|
||||
" \"raw\": [\"Hello\\nWorld\", 123.456]\n" // no indentation within raw value
|
||||
"}",
|
||||
buffer.GetString());
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,592 +0,0 @@
|
||||
// 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/internal/regex.h"
|
||||
|
||||
using namespace rapidjson::internal;
|
||||
|
||||
TEST(Regex, Single) {
|
||||
Regex re("a");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
}
|
||||
|
||||
TEST(Regex, Concatenation) {
|
||||
Regex re("abc");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abc"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("abcd"));
|
||||
}
|
||||
|
||||
TEST(Regex, Alternation1) {
|
||||
Regex re("abab|abbb");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abab"));
|
||||
EXPECT_TRUE(re.Match("abbb"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("ababa"));
|
||||
EXPECT_FALSE(re.Match("abb"));
|
||||
EXPECT_FALSE(re.Match("abbbb"));
|
||||
}
|
||||
|
||||
TEST(Regex, Alternation2) {
|
||||
Regex re("a|b|c");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match("c"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
}
|
||||
|
||||
TEST(Regex, Parenthesis1) {
|
||||
Regex re("(ab)c");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abc"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("abcd"));
|
||||
}
|
||||
|
||||
TEST(Regex, Parenthesis2) {
|
||||
Regex re("a(bc)");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abc"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("abcd"));
|
||||
}
|
||||
|
||||
TEST(Regex, Parenthesis3) {
|
||||
Regex re("(a|b)(c|d)");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("ac"));
|
||||
EXPECT_TRUE(re.Match("ad"));
|
||||
EXPECT_TRUE(re.Match("bc"));
|
||||
EXPECT_TRUE(re.Match("bd"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("cd"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrOne1) {
|
||||
Regex re("a?");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match(""));
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrOne2) {
|
||||
Regex re("a?b");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
EXPECT_FALSE(re.Match("bb"));
|
||||
EXPECT_FALSE(re.Match("ba"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrOne3) {
|
||||
Regex re("ab?");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
EXPECT_FALSE(re.Match("bb"));
|
||||
EXPECT_FALSE(re.Match("ba"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrOne4) {
|
||||
Regex re("a?b?");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match(""));
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
EXPECT_FALSE(re.Match("bb"));
|
||||
EXPECT_FALSE(re.Match("ba"));
|
||||
EXPECT_FALSE(re.Match("abc"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrOne5) {
|
||||
Regex re("a(ab)?b");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_TRUE(re.Match("aabb"));
|
||||
EXPECT_FALSE(re.Match("aab"));
|
||||
EXPECT_FALSE(re.Match("abb"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrMore1) {
|
||||
Regex re("a*");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match(""));
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("aa"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrMore2) {
|
||||
Regex re("a*b");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_TRUE(re.Match("aab"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("bb"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrMore3) {
|
||||
Regex re("a*b*");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match(""));
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("aa"));
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match("bb"));
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_TRUE(re.Match("aabb"));
|
||||
EXPECT_FALSE(re.Match("ba"));
|
||||
}
|
||||
|
||||
TEST(Regex, ZeroOrMore4) {
|
||||
Regex re("a(ab)*b");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_TRUE(re.Match("aabb"));
|
||||
EXPECT_TRUE(re.Match("aababb"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
}
|
||||
|
||||
TEST(Regex, OneOrMore1) {
|
||||
Regex re("a+");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("aa"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
}
|
||||
|
||||
TEST(Regex, OneOrMore2) {
|
||||
Regex re("a+b");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_TRUE(re.Match("aab"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
}
|
||||
|
||||
TEST(Regex, OneOrMore3) {
|
||||
Regex re("a+b+");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("ab"));
|
||||
EXPECT_TRUE(re.Match("aab"));
|
||||
EXPECT_TRUE(re.Match("abb"));
|
||||
EXPECT_TRUE(re.Match("aabb"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("ba"));
|
||||
}
|
||||
|
||||
TEST(Regex, OneOrMore4) {
|
||||
Regex re("a(ab)+b");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("aabb"));
|
||||
EXPECT_TRUE(re.Match("aababb"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("ab"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierExact1) {
|
||||
Regex re("ab{3}c");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abbbc"));
|
||||
EXPECT_FALSE(re.Match("ac"));
|
||||
EXPECT_FALSE(re.Match("abc"));
|
||||
EXPECT_FALSE(re.Match("abbc"));
|
||||
EXPECT_FALSE(re.Match("abbbbc"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierExact2) {
|
||||
Regex re("a(bc){3}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abcbcbcd"));
|
||||
EXPECT_FALSE(re.Match("ad"));
|
||||
EXPECT_FALSE(re.Match("abcd"));
|
||||
EXPECT_FALSE(re.Match("abcbcd"));
|
||||
EXPECT_FALSE(re.Match("abcbcbcbcd"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierExact3) {
|
||||
Regex re("a(b|c){3}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abbbd"));
|
||||
EXPECT_TRUE(re.Match("acccd"));
|
||||
EXPECT_TRUE(re.Match("abcbd"));
|
||||
EXPECT_FALSE(re.Match("ad"));
|
||||
EXPECT_FALSE(re.Match("abbd"));
|
||||
EXPECT_FALSE(re.Match("accccd"));
|
||||
EXPECT_FALSE(re.Match("abbbbd"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierMin1) {
|
||||
Regex re("ab{3,}c");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abbbc"));
|
||||
EXPECT_TRUE(re.Match("abbbbc"));
|
||||
EXPECT_TRUE(re.Match("abbbbbc"));
|
||||
EXPECT_FALSE(re.Match("ac"));
|
||||
EXPECT_FALSE(re.Match("abc"));
|
||||
EXPECT_FALSE(re.Match("abbc"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierMin2) {
|
||||
Regex re("a(bc){3,}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abcbcbcd"));
|
||||
EXPECT_TRUE(re.Match("abcbcbcbcd"));
|
||||
EXPECT_FALSE(re.Match("ad"));
|
||||
EXPECT_FALSE(re.Match("abcd"));
|
||||
EXPECT_FALSE(re.Match("abcbcd"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierMin3) {
|
||||
Regex re("a(b|c){3,}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abbbd"));
|
||||
EXPECT_TRUE(re.Match("acccd"));
|
||||
EXPECT_TRUE(re.Match("abcbd"));
|
||||
EXPECT_TRUE(re.Match("accccd"));
|
||||
EXPECT_TRUE(re.Match("abbbbd"));
|
||||
EXPECT_FALSE(re.Match("ad"));
|
||||
EXPECT_FALSE(re.Match("abbd"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierMinMax1) {
|
||||
Regex re("ab{3,5}c");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abbbc"));
|
||||
EXPECT_TRUE(re.Match("abbbbc"));
|
||||
EXPECT_TRUE(re.Match("abbbbbc"));
|
||||
EXPECT_FALSE(re.Match("ac"));
|
||||
EXPECT_FALSE(re.Match("abc"));
|
||||
EXPECT_FALSE(re.Match("abbc"));
|
||||
EXPECT_FALSE(re.Match("abbbbbbc"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierMinMax2) {
|
||||
Regex re("a(bc){3,5}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abcbcbcd"));
|
||||
EXPECT_TRUE(re.Match("abcbcbcbcd"));
|
||||
EXPECT_TRUE(re.Match("abcbcbcbcbcd"));
|
||||
EXPECT_FALSE(re.Match("ad"));
|
||||
EXPECT_FALSE(re.Match("abcd"));
|
||||
EXPECT_FALSE(re.Match("abcbcd"));
|
||||
EXPECT_FALSE(re.Match("abcbcbcbcbcbcd"));
|
||||
}
|
||||
|
||||
TEST(Regex, QuantifierMinMax3) {
|
||||
Regex re("a(b|c){3,5}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("abbbd"));
|
||||
EXPECT_TRUE(re.Match("acccd"));
|
||||
EXPECT_TRUE(re.Match("abcbd"));
|
||||
EXPECT_TRUE(re.Match("accccd"));
|
||||
EXPECT_TRUE(re.Match("abbbbd"));
|
||||
EXPECT_TRUE(re.Match("acccccd"));
|
||||
EXPECT_TRUE(re.Match("abbbbbd"));
|
||||
EXPECT_FALSE(re.Match("ad"));
|
||||
EXPECT_FALSE(re.Match("abbd"));
|
||||
EXPECT_FALSE(re.Match("accccccd"));
|
||||
EXPECT_FALSE(re.Match("abbbbbbd"));
|
||||
}
|
||||
|
||||
// Issue538
|
||||
TEST(Regex, QuantifierMinMax4) {
|
||||
Regex re("a(b|c){0,3}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("ad"));
|
||||
EXPECT_TRUE(re.Match("abd"));
|
||||
EXPECT_TRUE(re.Match("acd"));
|
||||
EXPECT_TRUE(re.Match("abbd"));
|
||||
EXPECT_TRUE(re.Match("accd"));
|
||||
EXPECT_TRUE(re.Match("abcd"));
|
||||
EXPECT_TRUE(re.Match("abbbd"));
|
||||
EXPECT_TRUE(re.Match("acccd"));
|
||||
EXPECT_FALSE(re.Match("abbbbd"));
|
||||
EXPECT_FALSE(re.Match("add"));
|
||||
EXPECT_FALSE(re.Match("accccd"));
|
||||
EXPECT_FALSE(re.Match("abcbcd"));
|
||||
}
|
||||
|
||||
// Issue538
|
||||
TEST(Regex, QuantifierMinMax5) {
|
||||
Regex re("a(b|c){0,}d");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("ad"));
|
||||
EXPECT_TRUE(re.Match("abd"));
|
||||
EXPECT_TRUE(re.Match("acd"));
|
||||
EXPECT_TRUE(re.Match("abbd"));
|
||||
EXPECT_TRUE(re.Match("accd"));
|
||||
EXPECT_TRUE(re.Match("abcd"));
|
||||
EXPECT_TRUE(re.Match("abbbd"));
|
||||
EXPECT_TRUE(re.Match("acccd"));
|
||||
EXPECT_TRUE(re.Match("abbbbd"));
|
||||
EXPECT_TRUE(re.Match("accccd"));
|
||||
EXPECT_TRUE(re.Match("abcbcd"));
|
||||
EXPECT_FALSE(re.Match("add"));
|
||||
EXPECT_FALSE(re.Match("aad"));
|
||||
}
|
||||
|
||||
#define EURO "\xE2\x82\xAC" // "\xE2\x82\xAC" is UTF-8 sequence of Euro sign U+20AC
|
||||
|
||||
TEST(Regex, Unicode) {
|
||||
Regex re("a" EURO "+b");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a" EURO "b"));
|
||||
EXPECT_TRUE(re.Match("a" EURO EURO "b"));
|
||||
EXPECT_FALSE(re.Match("a?b"));
|
||||
EXPECT_FALSE(re.Match("a" EURO "\xAC" "b")); // unaware of UTF-8 will match
|
||||
}
|
||||
|
||||
TEST(Regex, AnyCharacter) {
|
||||
Regex re(".");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match(EURO));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange1) {
|
||||
Regex re("[abc]");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match("c"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("`"));
|
||||
EXPECT_FALSE(re.Match("d"));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange2) {
|
||||
Regex re("[^abc]");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("`"));
|
||||
EXPECT_TRUE(re.Match("d"));
|
||||
EXPECT_FALSE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("c"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange3) {
|
||||
Regex re("[a-c]");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("b"));
|
||||
EXPECT_TRUE(re.Match("c"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("`"));
|
||||
EXPECT_FALSE(re.Match("d"));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange4) {
|
||||
Regex re("[^a-c]");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("`"));
|
||||
EXPECT_TRUE(re.Match("d"));
|
||||
EXPECT_FALSE(re.Match("a"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
EXPECT_FALSE(re.Match("c"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("aa"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange5) {
|
||||
Regex re("[-]");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("-"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("a"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange6) {
|
||||
Regex re("[a-]");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("-"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("`"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange7) {
|
||||
Regex re("[-a]");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("a"));
|
||||
EXPECT_TRUE(re.Match("-"));
|
||||
EXPECT_FALSE(re.Match(""));
|
||||
EXPECT_FALSE(re.Match("`"));
|
||||
EXPECT_FALSE(re.Match("b"));
|
||||
}
|
||||
|
||||
TEST(Regex, CharacterRange8) {
|
||||
Regex re("[a-zA-Z0-9]*");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("Milo"));
|
||||
EXPECT_TRUE(re.Match("MT19937"));
|
||||
EXPECT_TRUE(re.Match("43"));
|
||||
EXPECT_FALSE(re.Match("a_b"));
|
||||
EXPECT_FALSE(re.Match("!"));
|
||||
}
|
||||
|
||||
TEST(Regex, Search) {
|
||||
Regex re("abc");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Search("abc"));
|
||||
EXPECT_TRUE(re.Search("_abc"));
|
||||
EXPECT_TRUE(re.Search("abc_"));
|
||||
EXPECT_TRUE(re.Search("_abc_"));
|
||||
EXPECT_TRUE(re.Search("__abc__"));
|
||||
EXPECT_TRUE(re.Search("abcabc"));
|
||||
EXPECT_FALSE(re.Search("a"));
|
||||
EXPECT_FALSE(re.Search("ab"));
|
||||
EXPECT_FALSE(re.Search("bc"));
|
||||
EXPECT_FALSE(re.Search("cba"));
|
||||
}
|
||||
|
||||
TEST(Regex, Search_BeginAnchor) {
|
||||
Regex re("^abc");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Search("abc"));
|
||||
EXPECT_TRUE(re.Search("abc_"));
|
||||
EXPECT_TRUE(re.Search("abcabc"));
|
||||
EXPECT_FALSE(re.Search("_abc"));
|
||||
EXPECT_FALSE(re.Search("_abc_"));
|
||||
EXPECT_FALSE(re.Search("a"));
|
||||
EXPECT_FALSE(re.Search("ab"));
|
||||
EXPECT_FALSE(re.Search("bc"));
|
||||
EXPECT_FALSE(re.Search("cba"));
|
||||
}
|
||||
|
||||
TEST(Regex, Search_EndAnchor) {
|
||||
Regex re("abc$");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Search("abc"));
|
||||
EXPECT_TRUE(re.Search("_abc"));
|
||||
EXPECT_TRUE(re.Search("abcabc"));
|
||||
EXPECT_FALSE(re.Search("abc_"));
|
||||
EXPECT_FALSE(re.Search("_abc_"));
|
||||
EXPECT_FALSE(re.Search("a"));
|
||||
EXPECT_FALSE(re.Search("ab"));
|
||||
EXPECT_FALSE(re.Search("bc"));
|
||||
EXPECT_FALSE(re.Search("cba"));
|
||||
}
|
||||
|
||||
TEST(Regex, Search_BothAnchor) {
|
||||
Regex re("^abc$");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Search("abc"));
|
||||
EXPECT_FALSE(re.Search(""));
|
||||
EXPECT_FALSE(re.Search("a"));
|
||||
EXPECT_FALSE(re.Search("b"));
|
||||
EXPECT_FALSE(re.Search("ab"));
|
||||
EXPECT_FALSE(re.Search("abcd"));
|
||||
}
|
||||
|
||||
TEST(Regex, Escape) {
|
||||
const char* s = "\\^\\$\\|\\(\\)\\?\\*\\+\\.\\[\\]\\{\\}\\\\\\f\\n\\r\\t\\v[\\b][\\[][\\]]";
|
||||
Regex re(s);
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
EXPECT_TRUE(re.Match("^$|()?*+.[]{}\\\x0C\n\r\t\x0B\b[]"));
|
||||
EXPECT_FALSE(re.Match(s)); // Not escaping
|
||||
}
|
||||
|
||||
TEST(Regex, Invalid) {
|
||||
#define TEST_INVALID(s) \
|
||||
{\
|
||||
Regex re(s);\
|
||||
EXPECT_FALSE(re.IsValid());\
|
||||
}
|
||||
|
||||
TEST_INVALID("");
|
||||
TEST_INVALID("a|");
|
||||
TEST_INVALID("()");
|
||||
TEST_INVALID(")");
|
||||
TEST_INVALID("(a))");
|
||||
TEST_INVALID("(a|)");
|
||||
TEST_INVALID("(a||b)");
|
||||
TEST_INVALID("(|b)");
|
||||
TEST_INVALID("?");
|
||||
TEST_INVALID("*");
|
||||
TEST_INVALID("+");
|
||||
TEST_INVALID("{");
|
||||
TEST_INVALID("{}");
|
||||
TEST_INVALID("a{a}");
|
||||
TEST_INVALID("a{0}");
|
||||
TEST_INVALID("a{-1}");
|
||||
TEST_INVALID("a{}");
|
||||
// TEST_INVALID("a{0,}"); // Support now
|
||||
TEST_INVALID("a{,0}");
|
||||
TEST_INVALID("a{1,0}");
|
||||
TEST_INVALID("a{-1,0}");
|
||||
TEST_INVALID("a{-1,1}");
|
||||
TEST_INVALID("a{4294967296}"); // overflow of unsigned
|
||||
TEST_INVALID("a{1a}");
|
||||
TEST_INVALID("[");
|
||||
TEST_INVALID("[]");
|
||||
TEST_INVALID("[^]");
|
||||
TEST_INVALID("[\\a]");
|
||||
TEST_INVALID("\\a");
|
||||
|
||||
#undef TEST_INVALID
|
||||
}
|
||||
|
||||
TEST(Regex, Issue538) {
|
||||
Regex re("^[0-9]+(\\\\.[0-9]+){0,2}");
|
||||
EXPECT_TRUE(re.IsValid());
|
||||
}
|
||||
|
||||
TEST(Regex, Issue583) {
|
||||
Regex re("[0-9]{99999}");
|
||||
ASSERT_TRUE(re.IsValid());
|
||||
}
|
||||
|
||||
#undef EURO
|
File diff suppressed because it is too large
Load Diff
@ -1,215 +0,0 @@
|
||||
// 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.
|
||||
|
||||
// Since Travis CI installs old Valgrind 3.7.0, which fails with some SSE4.2
|
||||
// The unit tests prefix with SIMD should be skipped by Valgrind test
|
||||
|
||||
// __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_NAMESPACE rapidjson_simd
|
||||
|
||||
#include "unittest.h"
|
||||
|
||||
#include "rapidjson/reader.h"
|
||||
#include "rapidjson/writer.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(effc++)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson_simd;
|
||||
|
||||
#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
|
||||
|
||||
template <typename StreamType>
|
||||
void TestSkipWhitespace() {
|
||||
for (size_t step = 1; step < 32; step++) {
|
||||
char buffer[1025];
|
||||
for (size_t i = 0; i < 1024; i++)
|
||||
buffer[i] = " \t\r\n"[i % 4];
|
||||
for (size_t i = 0; i < 1024; i += step)
|
||||
buffer[i] = 'X';
|
||||
buffer[1024] = '\0';
|
||||
|
||||
StreamType s(buffer);
|
||||
size_t i = 0;
|
||||
for (;;) {
|
||||
SkipWhitespace(s);
|
||||
if (s.Peek() == '\0')
|
||||
break;
|
||||
EXPECT_EQ(i, s.Tell());
|
||||
EXPECT_EQ('X', s.Take());
|
||||
i += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
|
||||
TestSkipWhitespace<StringStream>();
|
||||
TestSkipWhitespace<InsituStringStream>();
|
||||
}
|
||||
|
||||
TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
|
||||
for (size_t step = 1; step < 32; step++) {
|
||||
char buffer[1024];
|
||||
for (size_t i = 0; i < 1024; i++)
|
||||
buffer[i] = " \t\r\n"[i % 4];
|
||||
for (size_t i = 0; i < 1024; i += step)
|
||||
buffer[i] = 'X';
|
||||
|
||||
MemoryStream ms(buffer, 1024);
|
||||
EncodedInputStream<UTF8<>, MemoryStream> s(ms);
|
||||
size_t i = 0;
|
||||
for (;;) {
|
||||
SkipWhitespace(s);
|
||||
if (s.Peek() == '\0')
|
||||
break;
|
||||
//EXPECT_EQ(i, s.Tell());
|
||||
EXPECT_EQ('X', s.Take());
|
||||
i += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnescapedStringHandler> {
|
||||
bool String(const char* str, size_t length, bool) {
|
||||
memcpy(buffer, str, length + 1);
|
||||
return true;
|
||||
}
|
||||
char buffer[1024 + 5 + 32];
|
||||
};
|
||||
|
||||
template <unsigned parseFlags, typename StreamType>
|
||||
void TestScanCopyUnescapedString() {
|
||||
char buffer[1024 + 5 + 32];
|
||||
char backup[1024 + 5 + 32];
|
||||
|
||||
// Test "ABCDABCD...\\"
|
||||
for (size_t offset = 0; offset < 32; offset++) {
|
||||
for (size_t step = 0; step < 1024; step++) {
|
||||
char* json = buffer + offset;
|
||||
char *p = json;
|
||||
*p++ = '\"';
|
||||
for (size_t i = 0; i < step; i++)
|
||||
*p++ = "ABCD"[i % 4];
|
||||
*p++ = '\\';
|
||||
*p++ = '\\';
|
||||
*p++ = '\"';
|
||||
*p++ = '\0';
|
||||
strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
|
||||
|
||||
StreamType s(json);
|
||||
Reader reader;
|
||||
ScanCopyUnescapedStringHandler h;
|
||||
reader.Parse<parseFlags>(s, h);
|
||||
EXPECT_TRUE(memcmp(h.buffer, backup + 1, step) == 0);
|
||||
EXPECT_EQ('\\', h.buffer[step]); // escaped
|
||||
EXPECT_EQ('\0', h.buffer[step + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Test "\\ABCDABCD..."
|
||||
for (size_t offset = 0; offset < 32; offset++) {
|
||||
for (size_t step = 0; step < 1024; step++) {
|
||||
char* json = buffer + offset;
|
||||
char *p = json;
|
||||
*p++ = '\"';
|
||||
*p++ = '\\';
|
||||
*p++ = '\\';
|
||||
for (size_t i = 0; i < step; i++)
|
||||
*p++ = "ABCD"[i % 4];
|
||||
*p++ = '\"';
|
||||
*p++ = '\0';
|
||||
strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
|
||||
|
||||
StreamType s(json);
|
||||
Reader reader;
|
||||
ScanCopyUnescapedStringHandler h;
|
||||
reader.Parse<parseFlags>(s, h);
|
||||
EXPECT_TRUE(memcmp(h.buffer + 1, backup + 3, step) == 0);
|
||||
EXPECT_EQ('\\', h.buffer[0]); // escaped
|
||||
EXPECT_EQ('\0', h.buffer[step + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
|
||||
TestScanCopyUnescapedString<kParseDefaultFlags, StringStream>();
|
||||
TestScanCopyUnescapedString<kParseInsituFlag, InsituStringStream>();
|
||||
}
|
||||
|
||||
TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
|
||||
char buffer[2048 + 1 + 32];
|
||||
for (size_t offset = 0; offset < 32; offset++) {
|
||||
for (size_t step = 0; step < 1024; step++) {
|
||||
char* s = buffer + offset;
|
||||
char* p = s;
|
||||
for (size_t i = 0; i < step; i++)
|
||||
*p++ = "ABCD"[i % 4];
|
||||
char escape = "\0\n\\\""[step % 4];
|
||||
*p++ = escape;
|
||||
for (size_t i = 0; i < step; i++)
|
||||
*p++ = "ABCD"[i % 4];
|
||||
|
||||
StringBuffer sb;
|
||||
Writer<StringBuffer> writer(sb);
|
||||
writer.String(s, SizeType(step * 2 + 1));
|
||||
const char* q = sb.GetString();
|
||||
EXPECT_EQ('\"', *q++);
|
||||
for (size_t i = 0; i < step; i++)
|
||||
EXPECT_EQ("ABCD"[i % 4], *q++);
|
||||
if (escape == '\0') {
|
||||
EXPECT_EQ('\\', *q++);
|
||||
EXPECT_EQ('u', *q++);
|
||||
EXPECT_EQ('0', *q++);
|
||||
EXPECT_EQ('0', *q++);
|
||||
EXPECT_EQ('0', *q++);
|
||||
EXPECT_EQ('0', *q++);
|
||||
}
|
||||
else if (escape == '\n') {
|
||||
EXPECT_EQ('\\', *q++);
|
||||
EXPECT_EQ('n', *q++);
|
||||
}
|
||||
else if (escape == '\\') {
|
||||
EXPECT_EQ('\\', *q++);
|
||||
EXPECT_EQ('\\', *q++);
|
||||
}
|
||||
else if (escape == '\"') {
|
||||
EXPECT_EQ('\\', *q++);
|
||||
EXPECT_EQ('\"', *q++);
|
||||
}
|
||||
for (size_t i = 0; i < step; i++)
|
||||
EXPECT_EQ("ABCD"[i % 4], *q++);
|
||||
EXPECT_EQ('\"', *q++);
|
||||
EXPECT_EQ('\0', *q++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
@ -1,30 +0,0 @@
|
||||
// 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/internal/strfunc.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace rapidjson::internal;
|
||||
|
||||
TEST(StrFunc, CountStringCodePoint) {
|
||||
SizeType count;
|
||||
EXPECT_TRUE(CountStringCodePoint<UTF8<> >("", 0, &count));
|
||||
EXPECT_EQ(0u, count);
|
||||
EXPECT_TRUE(CountStringCodePoint<UTF8<> >("Hello", 5, &count));
|
||||
EXPECT_EQ(5u, count);
|
||||
EXPECT_TRUE(CountStringCodePoint<UTF8<> >("\xC2\xA2\xE2\x82\xAC\xF0\x9D\x84\x9E", 9, &count)); // cents euro G-clef
|
||||
EXPECT_EQ(3u, count);
|
||||
EXPECT_FALSE(CountStringCodePoint<UTF8<> >("\xC2\xA2\xE2\x82\xAC\xF0\x9D\x84\x9E\x80", 10, &count));
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
// 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/stringbuffer.h"
|
||||
#include "rapidjson/writer.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
TEST(StringBuffer, InitialSize) {
|
||||
StringBuffer buffer;
|
||||
EXPECT_EQ(0u, buffer.GetSize());
|
||||
EXPECT_STREQ("", buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(StringBuffer, Put) {
|
||||
StringBuffer buffer;
|
||||
buffer.Put('A');
|
||||
|
||||
EXPECT_EQ(1u, buffer.GetSize());
|
||||
EXPECT_STREQ("A", buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(StringBuffer, PutN_Issue672) {
|
||||
GenericStringBuffer<UTF8<>, MemoryPoolAllocator<> > buffer;
|
||||
EXPECT_EQ(0, buffer.GetSize());
|
||||
rapidjson::PutN(buffer, ' ', 1);
|
||||
EXPECT_EQ(1, buffer.GetSize());
|
||||
}
|
||||
|
||||
TEST(StringBuffer, Clear) {
|
||||
StringBuffer buffer;
|
||||
buffer.Put('A');
|
||||
buffer.Put('B');
|
||||
buffer.Put('C');
|
||||
buffer.Clear();
|
||||
|
||||
EXPECT_EQ(0u, buffer.GetSize());
|
||||
EXPECT_STREQ("", buffer.GetString());
|
||||
}
|
||||
|
||||
TEST(StringBuffer, Push) {
|
||||
StringBuffer buffer;
|
||||
buffer.Push(5);
|
||||
|
||||
EXPECT_EQ(5u, buffer.GetSize());
|
||||
|
||||
// Causes sudden expansion to make the stack's capacity equal to size
|
||||
buffer.Push(65536u);
|
||||
EXPECT_EQ(5u + 65536u, buffer.GetSize());
|
||||
}
|
||||
|
||||
TEST(StringBuffer, Pop) {
|
||||
StringBuffer buffer;
|
||||
buffer.Put('A');
|
||||
buffer.Put('B');
|
||||
buffer.Put('C');
|
||||
buffer.Put('D');
|
||||
buffer.Put('E');
|
||||
buffer.Pop(3);
|
||||
|
||||
EXPECT_EQ(2u, buffer.GetSize());
|
||||
EXPECT_STREQ("AB", buffer.GetString());
|
||||
}
|
||||
|
||||
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
|
||||
#if 0 // Many old compiler does not support these. Turn it off temporaily.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
TEST(StringBuffer, Traits) {
|
||||
static_assert( std::is_constructible<StringBuffer>::value, "");
|
||||
static_assert( std::is_default_constructible<StringBuffer>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(!std::is_copy_constructible<StringBuffer>::value, "");
|
||||
#endif
|
||||
static_assert( std::is_move_constructible<StringBuffer>::value, "");
|
||||
|
||||
static_assert(!std::is_nothrow_constructible<StringBuffer>::value, "");
|
||||
static_assert(!std::is_nothrow_default_constructible<StringBuffer>::value, "");
|
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1800
|
||||
static_assert(!std::is_nothrow_copy_constructible<StringBuffer>::value, "");
|
||||
static_assert(!std::is_nothrow_move_constructible<StringBuffer>::value, "");
|
||||
#endif
|
||||
|
||||
static_assert( std::is_assignable<StringBuffer,StringBuffer>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(!std::is_copy_assignable<StringBuffer>::value, "");
|
||||
#endif
|
||||
static_assert( std::is_move_assignable<StringBuffer>::value, "");
|
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1800
|
||||
static_assert(!std::is_nothrow_assignable<StringBuffer, StringBuffer>::value, "");
|
||||
#endif
|
||||
|
||||
static_assert(!std::is_nothrow_copy_assignable<StringBuffer>::value, "");
|
||||
static_assert(!std::is_nothrow_move_assignable<StringBuffer>::value, "");
|
||||
|
||||
static_assert( std::is_destructible<StringBuffer>::value, "");
|
||||
#ifndef _MSC_VER
|
||||
static_assert(std::is_nothrow_destructible<StringBuffer>::value, "");
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST(StringBuffer, MoveConstructor) {
|
||||
StringBuffer x;
|
||||
x.Put('A');
|
||||
x.Put('B');
|
||||
x.Put('C');
|
||||
x.Put('D');
|
||||
|
||||
EXPECT_EQ(4u, x.GetSize());
|
||||
EXPECT_STREQ("ABCD", x.GetString());
|
||||
|
||||
// StringBuffer y(x); // does not compile (!is_copy_constructible)
|
||||
StringBuffer y(std::move(x));
|
||||
EXPECT_EQ(0u, x.GetSize());
|
||||
EXPECT_EQ(4u, y.GetSize());
|
||||
EXPECT_STREQ("ABCD", y.GetString());
|
||||
|
||||
// StringBuffer z = y; // does not compile (!is_copy_assignable)
|
||||
StringBuffer z = std::move(y);
|
||||
EXPECT_EQ(0u, y.GetSize());
|
||||
EXPECT_EQ(4u, z.GetSize());
|
||||
EXPECT_STREQ("ABCD", z.GetString());
|
||||
}
|
||||
|
||||
TEST(StringBuffer, MoveAssignment) {
|
||||
StringBuffer x;
|
||||
x.Put('A');
|
||||
x.Put('B');
|
||||
x.Put('C');
|
||||
x.Put('D');
|
||||
|
||||
EXPECT_EQ(4u, x.GetSize());
|
||||
EXPECT_STREQ("ABCD", x.GetString());
|
||||
|
||||
StringBuffer y;
|
||||
// y = x; // does not compile (!is_copy_assignable)
|
||||
y = std::move(x);
|
||||
EXPECT_EQ(0u, x.GetSize());
|
||||
EXPECT_EQ(4u, y.GetSize());
|
||||
EXPECT_STREQ("ABCD", y.GetString());
|
||||
}
|
||||
|
||||
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
@ -1,132 +0,0 @@
|
||||
// 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/internal/strtod.h"
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_PUSH
|
||||
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||
#endif
|
||||
|
||||
#define BIGINTEGER_LITERAL(s) BigInteger(s, sizeof(s) - 1)
|
||||
|
||||
using namespace rapidjson::internal;
|
||||
|
||||
TEST(Strtod, CheckApproximationCase) {
|
||||
static const int kSignificandSize = 52;
|
||||
static const int kExponentBias = 0x3FF;
|
||||
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||
|
||||
// http://www.exploringbinary.com/using-integers-to-check-a-floating-point-approximation/
|
||||
// Let b = 0x1.465a72e467d88p-149
|
||||
// = 5741268244528520 x 2^-201
|
||||
union {
|
||||
double d;
|
||||
uint64_t u;
|
||||
}u;
|
||||
u.u = 0x465a72e467d88 | ((static_cast<uint64_t>(-149 + kExponentBias)) << kSignificandSize);
|
||||
const double b = u.d;
|
||||
const uint64_t bInt = (u.u & kSignificandMask) | kHiddenBit;
|
||||
const int bExp = static_cast<int>(((u.u & kExponentMask) >> kSignificandSize) - kExponentBias - kSignificandSize);
|
||||
EXPECT_DOUBLE_EQ(1.7864e-45, b);
|
||||
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x001465a7, 0x2e467d88), bInt);
|
||||
EXPECT_EQ(-201, bExp);
|
||||
|
||||
// Let d = 17864 x 10-49
|
||||
const char dInt[] = "17864";
|
||||
const int dExp = -49;
|
||||
|
||||
// Let h = 2^(bExp-1)
|
||||
const int hExp = bExp - 1;
|
||||
EXPECT_EQ(-202, hExp);
|
||||
|
||||
int dS_Exp2 = 0;
|
||||
int dS_Exp5 = 0;
|
||||
int bS_Exp2 = 0;
|
||||
int bS_Exp5 = 0;
|
||||
int hS_Exp2 = 0;
|
||||
int hS_Exp5 = 0;
|
||||
|
||||
// Adjust for decimal exponent
|
||||
if (dExp >= 0) {
|
||||
dS_Exp2 += dExp;
|
||||
dS_Exp5 += dExp;
|
||||
}
|
||||
else {
|
||||
bS_Exp2 -= dExp;
|
||||
bS_Exp5 -= dExp;
|
||||
hS_Exp2 -= dExp;
|
||||
hS_Exp5 -= dExp;
|
||||
}
|
||||
|
||||
// Adjust for binary exponent
|
||||
if (bExp >= 0)
|
||||
bS_Exp2 += bExp;
|
||||
else {
|
||||
dS_Exp2 -= bExp;
|
||||
hS_Exp2 -= bExp;
|
||||
}
|
||||
|
||||
// Adjust for half ulp exponent
|
||||
if (hExp >= 0)
|
||||
hS_Exp2 += hExp;
|
||||
else {
|
||||
dS_Exp2 -= hExp;
|
||||
bS_Exp2 -= hExp;
|
||||
}
|
||||
|
||||
// Remove common power of two factor from all three scaled values
|
||||
int common_Exp2 = std::min(dS_Exp2, std::min(bS_Exp2, hS_Exp2));
|
||||
dS_Exp2 -= common_Exp2;
|
||||
bS_Exp2 -= common_Exp2;
|
||||
hS_Exp2 -= common_Exp2;
|
||||
|
||||
EXPECT_EQ(153, dS_Exp2);
|
||||
EXPECT_EQ(0, dS_Exp5);
|
||||
EXPECT_EQ(1, bS_Exp2);
|
||||
EXPECT_EQ(49, bS_Exp5);
|
||||
EXPECT_EQ(0, hS_Exp2);
|
||||
EXPECT_EQ(49, hS_Exp5);
|
||||
|
||||
BigInteger dS = BIGINTEGER_LITERAL(dInt);
|
||||
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<size_t>(dS_Exp2);
|
||||
|
||||
BigInteger bS(bInt);
|
||||
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<size_t>(bS_Exp2);
|
||||
|
||||
BigInteger hS(1);
|
||||
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<size_t>(hS_Exp2);
|
||||
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994138521801764465966248930731085529088") == dS);
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("203970822259994122305215569213032722473144531250000") == bS);
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("17763568394002504646778106689453125") == hS);
|
||||
|
||||
EXPECT_EQ(1, dS.Compare(bS));
|
||||
|
||||
BigInteger delta(0);
|
||||
EXPECT_FALSE(dS.Difference(bS, &delta));
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta);
|
||||
EXPECT_TRUE(bS.Difference(dS, &delta));
|
||||
EXPECT_TRUE(BIGINTEGER_LITERAL("16216586195252933526457586554279088") == delta);
|
||||
|
||||
EXPECT_EQ(-1, delta.Compare(hS));
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
RAPIDJSON_DIAG_POP
|
||||
#endif
|
@ -1,51 +0,0 @@
|
||||
// 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 };
|
||||
(void)memoryState;
|
||||
_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 +0,0 @@
|
||||
// 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_
|
File diff suppressed because it is too large
Load Diff
@ -1,497 +0,0 @@
|
||||
// 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"
|
||||
#include "rapidjson/memorybuffer.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, ScanWriteUnescapedString) {
|
||||
const char json[] = "[\" \\\"0123456789ABCDEF\"]";
|
||||
// ^ scanning stops here.
|
||||
char buffer2[sizeof(json) + 32];
|
||||
|
||||
// Use different offset to test different alignments
|
||||
for (int i = 0; i < 32; i++) {
|
||||
char* p = buffer2 + i;
|
||||
memcpy(p, json, sizeof(json));
|
||||
TEST_ROUNDTRIP(p);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
// UTF8 -> TargetEncoding -> UTF8
|
||||
template <typename TargetEncoding>
|
||||
void TestTranscode(const char* json) {
|
||||
StringStream s(json);
|
||||
GenericStringBuffer<TargetEncoding> buffer;
|
||||
Writer<GenericStringBuffer<TargetEncoding>, UTF8<>, TargetEncoding> writer(buffer);
|
||||
Reader reader;
|
||||
reader.Parse(s, writer);
|
||||
|
||||
StringBuffer buffer2;
|
||||
Writer<StringBuffer> writer2(buffer2);
|
||||
GenericReader<TargetEncoding, UTF8<> > reader2;
|
||||
GenericStringStream<TargetEncoding> s2(buffer.GetString());
|
||||
reader2.Parse(s2, writer2);
|
||||
|
||||
EXPECT_STREQ(json, buffer2.GetString());
|
||||
}
|
||||
|
||||
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
|
||||
TestTranscode<UTF8<> >(json);
|
||||
|
||||
// UTF8 -> ASCII -> UTF8
|
||||
TestTranscode<ASCII<> >(json);
|
||||
|
||||
// UTF8 -> UTF16 -> UTF8
|
||||
TestTranscode<UTF16<> >(json);
|
||||
|
||||
// UTF8 -> UTF32 -> UTF8
|
||||
TestTranscode<UTF32<> >(json);
|
||||
|
||||
// UTF8 -> AutoUTF -> UTF8
|
||||
UTFType types[] = { kUTF8, kUTF16LE , kUTF16BE, kUTF32LE , kUTF32BE };
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
StringStream s(json);
|
||||
MemoryBuffer buffer;
|
||||
AutoUTFOutputStream<unsigned, MemoryBuffer> os(buffer, types[i], true);
|
||||
Writer<AutoUTFOutputStream<unsigned, MemoryBuffer>, UTF8<>, AutoUTF<unsigned> > writer(os);
|
||||
Reader reader;
|
||||
reader.Parse(s, writer);
|
||||
|
||||
StringBuffer buffer2;
|
||||
Writer<StringBuffer> writer2(buffer2);
|
||||
GenericReader<AutoUTF<unsigned>, UTF8<> > reader2;
|
||||
MemoryStream s2(buffer.GetBuffer(), buffer.GetSize());
|
||||
AutoUTFInputStream<unsigned, MemoryStream> is(s2);
|
||||
reader2.Parse(is, 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());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Writer, NaN) {
|
||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
EXPECT_TRUE(internal::Double(nan).IsNan());
|
||||
StringBuffer buffer;
|
||||
{
|
||||
Writer<StringBuffer> writer(buffer);
|
||||
EXPECT_FALSE(writer.Double(nan));
|
||||
}
|
||||
{
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
|
||||
EXPECT_TRUE(writer.Double(nan));
|
||||
EXPECT_STREQ("NaN", buffer.GetString());
|
||||
}
|
||||
GenericStringBuffer<UTF16<> > buffer2;
|
||||
Writer<GenericStringBuffer<UTF16<> > > writer2(buffer2);
|
||||
EXPECT_FALSE(writer2.Double(nan));
|
||||
}
|
||||
|
||||
TEST(Writer, Inf) {
|
||||
double inf = std::numeric_limits<double>::infinity();
|
||||
|
||||
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));
|
||||
}
|
||||
{
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
|
||||
EXPECT_TRUE(writer.Double(inf));
|
||||
}
|
||||
{
|
||||
Writer<StringBuffer, UTF8<>, UTF8<>, CrtAllocator, kWriteNanAndInfFlag> writer(buffer);
|
||||
EXPECT_TRUE(writer.Double(-inf));
|
||||
}
|
||||
EXPECT_STREQ("Infinity-Infinity", buffer.GetString());
|
||||
}
|
||||
|
||||
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…
Reference in New Issue
Block a user