update rapidjson library (nw)

This commit is contained in:
Miodrag Milanovic 2016-03-08 11:39:25 +01:00
parent dfad813239
commit 1f352c6af8
112 changed files with 11185 additions and 9731 deletions

22
3rdparty/rapidjson/.gitattributes vendored Normal file
View File

@ -0,0 +1,22 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.cpp text
*.h text
*.txt text
*.md text
*.cmake text
*.svg text
*.dot text
*.yml text
*.in text
*.sh text
*.autopkg text
Dockerfile text
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.json binary

View File

@ -1,54 +1,175 @@
language: cpp
sudo: false
cache:
- ccache
compiler:
- clang
- gcc
addons:
apt:
packages: &default_packages
- cmake
- valgrind
env:
matrix:
- CONF=debug ARCH=x86_64 CXX11=ON
- CONF=release ARCH=x86_64 CXX11=ON
- CONF=debug ARCH=x86 CXX11=ON
- CONF=release ARCH=x86 CXX11=ON
- CONF=debug ARCH=x86_64 CXX11=OFF
- CONF=debug ARCH=x86 CXX11=OFF
global:
global:
- USE_CCACHE=1
- CCACHE_SLOPPINESS=pch_defines,time_macros
- CCACHE_COMPRESS=1
- CCACHE_MAXSIZE=100M
- ARCH_FLAGS_x86='-m32' # #266: don't use SSE on 32-bit
- ARCH_FLAGS_x86_64='-msse4.2' # use SSE4.2 on 64-bit
- GITHUB_REPO='miloyip/rapidjson'
- secure: "HrsaCb+N66EG1HR+LWH1u51SjaJyRwJEDzqJGYMB7LJ/bfqb9mWKF1fLvZGk46W5t7TVaXRDD5KHFx9DPWvKn4gRUVkwTHEy262ah5ORh8M6n/6VVVajeV/AYt2C0sswdkDBDO4Xq+xy5gdw3G8s1A4Inbm73pUh+6vx+7ltBbk="
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq cmake valgrind
- sudo apt-get --no-install-recommends install doxygen # Don't install LaTeX stuffs
- if [ "$ARCH" = "x86" ]; then sudo apt-get install -qq g++-multilib libc6-dbg:i386; fi
- if [ "$CC" = "gcc" ] && [ "$CONF" = "debug" ]; then sudo pip install cpp-coveralls; export GCOV_FLAGS='--coverage'; fi
install: true
matrix:
include:
# gcc
- env: CONF=release ARCH=x86 CXX11=ON
compiler: gcc
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- env: CONF=release ARCH=x86_64 CXX11=ON
compiler: gcc
- env: CONF=debug ARCH=x86 CXX11=OFF
compiler: gcc
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- env: CONF=debug ARCH=x86_64 CXX11=OFF
compiler: gcc
# clang
- env: CONF=debug ARCH=x86 CXX11=ON CCACHE_CPP2=yes
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- clang-3.7
- env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- clang-3.7
- env: CONF=debug ARCH=x86 CXX11=OFF CCACHE_CPP2=yes
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- clang-3.7
- env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- clang-3.7
- env: CONF=release ARCH=x86 CXX11=ON CCACHE_CPP2=yes
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
- clang-3.7
- env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
compiler: clang
addons:
apt:
sources:
- llvm-toolchain-precise-3.7
- ubuntu-toolchain-r-test
packages:
- *default_packages
- clang-3.7
# coverage report
- env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage'
compiler: gcc
cache:
- ccache
- pip
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
after_success:
- pip install --user cpp-coveralls
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
- env: CONF=debug ARCH=x86_64 GCOV_FLAGS='--coverage'
compiler: gcc
cache:
- ccache
- pip
addons:
apt:
packages:
- *default_packages
- g++-multilib
- libc6-dbg:i386
after_success:
- pip install --user cpp-coveralls
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
- script: # Documentation task
- cd build
- cmake .. -DRAPIDJSON_HAS_STDSTRING=ON -DCMAKE_VERBOSE_MAKEFILE=ON
- make travis_doc
cache: false
addons:
apt:
packages:
- doxygen
before_script:
# hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469),
# exposed by merging PR#163 (using -march=native)
- ccache -s
# hack to avoid Valgrind bug (https://bugs.kde.org/show_bug.cgi?id=326469),
# exposed by merging PR#163 (using -march=native)
# TODO: Since this bug is already fixed. Remove this when valgrind can be upgraded.
- sed -i "s/-march=native//" CMakeLists.txt
- mkdir build
- >
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
(cd build && cmake
-DRAPIDJSON_HAS_STDSTRING=ON
-DRAPIDJSON_BUILD_CXX11=$CXX11
-DCMAKE_VERBOSE_MAKEFILE=ON
-DCMAKE_BUILD_TYPE=$CONF
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
-DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS
..)
script:
- if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi
- >
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
(cd build && cmake
-DRAPIDJSON_HAS_STDSTRING=ON
-DRAPIDJSON_BUILD_CXX11=$CXX11
-DCMAKE_VERBOSE_MAKEFILE=ON
-DCMAKE_BUILD_TYPE=$CONF
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS $GCOV_FLAGS"
-DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS
..)
- cd build
- make tests
- make examples
- ctest -V `[ "$CONF" = "release" ] || echo "-E perftest"`
- make travis_doc
after_success:
- coveralls -r .. --gcov-options '\-lp' -e thirdparty -e example -e test -e build/CMakeFiles -e include/rapidjson/msinttypes -e include/rapidjson/internal/meta.h -e include/rapidjson/error/en.h
- make tests -j 2
- make examples -j 2
- ctest -j 2 -V `[ "$CONF" = "release" ] || echo "-E perftest"`

View File

@ -29,6 +29,15 @@ if(RAPIDJSON_HAS_STDSTRING)
add_definitions(-DRAPIDJSON_HAS_STDSTRING)
endif()
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} -march=native -Wall -Wextra -Werror")
if (RAPIDJSON_BUILD_CXX11)

View File

@ -1,3 +1,4 @@
os: Visual Studio 2015 CTP
version: 1.0.2.{build}
configuration:
@ -6,13 +7,25 @@ configuration:
environment:
matrix:
- VS_VERSION: 11
# - VS_VERSION: 9 2008
# VS_PLATFORM: win32
# - VS_VERSION: 9 2008
# VS_PLATFORM: x64
- VS_VERSION: 10 2010
VS_PLATFORM: win32
- VS_VERSION: 11
- VS_VERSION: 10 2010
VS_PLATFORM: x64
- VS_VERSION: 12
- VS_VERSION: 11 2012
VS_PLATFORM: win32
- VS_VERSION: 12
- VS_VERSION: 11 2012
VS_PLATFORM: x64
- VS_VERSION: 12 2013
VS_PLATFORM: win32
- VS_VERSION: 12 2013
VS_PLATFORM: x64
- VS_VERSION: 14 2015
VS_PLATFORM: win32
- VS_VERSION: 14 2015
VS_PLATFORM: x64
before_build:

View File

@ -2,17 +2,17 @@
## Status: experimental, shall be included in v1.1
JSON Schema is a draft standard for describing format of JSON. The schema itself is also a JSON. By validating a JSON with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema.
JSON Schema is a draft standard for describing the format of JSON data. The schema itself is also JSON data. By validating a JSON structure with JSON Schema, your code can safely access the DOM without manually checking types, or whether a key exists, etc. It can also ensure that the serialized JSON conform to a specified schema.
RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://json-schema.org/documentation.html). If you do not familiar with JSON Schema, you may refer to [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/).
RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http://json-schema.org/documentation.html). If you are not familiar with JSON Schema, you may refer to [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/).
[TOC]
## Basic Usage
First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into `SchemaDocument`.
First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`.
Secondly, construct a `SchemaValidator` with the `SchedmaDocument`. It is similar to a `Writer` in the sense of handling SAX events. So, you can use `document.Accept(validator)` to validate a document, and then check the validity.
Secondly, construct a `SchemaValidator` with the `SchemaDocument`. It is similar to a `Writer` in the sense of handling SAX events. So, you can use `document.Accept(validator)` to validate a document, and then check the validity.
~~~cpp
#include "rapidjson/schema.h"
@ -54,7 +54,7 @@ Some notes:
## Validation during parsing/serialization
Differ to most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files.
Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files.
### DOM parsing
@ -111,7 +111,7 @@ if (!reader.Parse(stream, validator)) {
}
~~~
This is exactly the method used in [schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The distinct advantage is low memory usage, no matter how big the JSON was (the memory usage depends on the complexity of the schema).
This is exactly the method used in the [schemavalidator](example/schemavalidator/schemavalidator.cpp) example. The distinct advantage is low memory usage, no matter how big the JSON was (the memory usage depends on the complexity of the schema).
If you need to handle the SAX events further, then you need to use the template class `GenericSchemaValidator` to set the output handler of the validator:
@ -213,7 +213,7 @@ For C++11 compiler, it is also possible to use the `std::regex` by defining `RAP
## Performance
Most C++ JSON libraries have not yet supporting JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js.
Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js.
That benchmark runs validations on [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite), in which some test suites and tests are excluded. We made the same benchmarking procedure in [`schematest.cpp`](test/perftest/schematest.cpp).

View File

@ -0,0 +1,8 @@
# BUILD: docker build -t rapidjson-debian .
# RUN: docker run -it -v "$PWD"/../..:/rapidjson rapidjson-debian
FROM debian:jessie
RUN apt-get update && apt-get install -y g++ cmake doxygen valgrind
ENTRYPOINT ["/bin/bash"]

View File

@ -1,6 +1,3 @@
# Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
# Copyright (c) 2013 Rafal Jeczalik (rjeczalik@gmail.com)
# Distributed under the MIT License (see license.txt file)
cmake_minimum_required(VERSION 2.8)
set(EXAMPLES
@ -8,6 +5,7 @@ set(EXAMPLES
condense
jsonx
messagereader
parsebyparts
pretty
prettyauto
schemavalidator
@ -22,7 +20,7 @@ include_directories("../include/")
add_definitions(-D__STDC_FORMAT_MACROS)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
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")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
@ -33,4 +31,8 @@ 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})

View File

@ -24,6 +24,7 @@ struct CapitalizeFilter {
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++)

View File

@ -57,6 +57,13 @@ public:
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") &&

View File

@ -0,0 +1,172 @@
// Example of parsing JSON to document by parts.
// Using C++11 threads
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700)
#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

View File

@ -12,6 +12,10 @@ struct MyHandler {
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;

View File

@ -9,26 +9,27 @@ int main() {
StringBuffer s;
Writer<StringBuffer> writer(s);
writer.StartObject();
writer.String("hello");
writer.String("world");
writer.String("t");
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.String("f");
writer.Key("f");
writer.Bool(false);
writer.String("n");
writer.Key("n");
writer.Null();
writer.String("i");
writer.Key("i");
writer.Uint(123);
writer.String("pi");
writer.Key("pi");
writer.Double(3.1416);
writer.String("a");
writer.StartArray();
writer.Key("a");
writer.StartArray(); // Between StartArray()/EndArray(),
for (unsigned i = 0; i < 4; i++)
writer.Uint(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;

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
#define RAPIDJSON_ENCODEDSTREAM_H_
#include "stream.h"
#include "memorystream.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
@ -62,6 +63,30 @@ private:
Ch current_;
};
//! Specialized for UTF8 MemoryStream.
template <>
class EncodedInputStream<UTF8<>, MemoryStream> {
public:
typedef UTF8<>::Ch Ch;
EncodedInputStream(MemoryStream& is) : is_(is) {
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
}
Ch Peek() const { return is_.Peek(); }
Ch Take() { return is_.Take(); }
size_t Tell() const { return is_.Tell(); }
// Not implemented
void Put(Ch) {}
void Flush() {}
Ch* PutBegin() { return 0; }
size_t PutEnd(Ch*) { return 0; }
MemoryStream& is_;
};
//! Output byte stream wrapper with statically bound encoding.
/*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.

View File

@ -29,6 +29,7 @@ namespace internal {
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
#endif
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
@ -148,7 +149,7 @@ inline char* WriteExponent(int K, char* buffer) {
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21) {
if (0 <= k && kk <= 21) {
// 1234e7 -> 12340000000
for (int i = length; i < kk; i++)
buffer[i] = '0';
@ -160,7 +161,7 @@ inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
// 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.';
if (length > kk + maxDecimalPlaces) {
if (0 > k + maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
@ -179,7 +180,7 @@ inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
buffer[1] = '.';
for (int i = 2; i < offset; i++)
buffer[i] = '0';
if (length + offset > maxDecimalPlaces) {
if (length - kk > maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = maxDecimalPlaces + 1; i > 2; i--)

View File

@ -20,6 +20,11 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
@ -98,7 +103,7 @@ private:
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
#ifdef __clang__
#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif

View File

@ -42,8 +42,8 @@ struct MemoryStream {
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }

View File

@ -74,6 +74,12 @@ public:
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
PrettyPrefix(kNumberType);
return Base::WriteString(str, length);
}
bool String(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
PrettyPrefix(kStringType);

View File

@ -159,7 +159,7 @@
*/
#ifndef RAPIDJSON_NO_INT64DEFINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#ifdef _MSC_VER
#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
#include "msinttypes/stdint.h"
#include "msinttypes/inttypes.h"
#else
@ -265,7 +265,8 @@
\param x pointer to align
Some machines require strict data alignment. Currently the default uses 4 bytes
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.
alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
User can customize by defining the RAPIDJSON_ALIGN function macro.
*/
#ifndef RAPIDJSON_ALIGN
#if RAPIDJSON_64BIT == 1
@ -288,6 +289,36 @@
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_48BITPOINTER_OPTIMIZATION
//! Use only lower 48-bit address for some pointers.
/*!
\ingroup RAPIDJSON_CONFIG
This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
The higher 16-bit can be used for storing other data.
\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
*/
#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
#else
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
#endif
#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
#if RAPIDJSON_64BIT != 1
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
#endif
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
#else
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
#define RAPIDJSON_GETPOINTER(type, p) (p)
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
@ -421,7 +452,7 @@ RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(__clang__)
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
#else
#define RAPIDJSON_LIKELY(x) x
#define RAPIDJSON_LIKELY(x) (x)
#endif
#endif
@ -434,7 +465,7 @@ RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(__clang__)
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define RAPIDJSON_UNLIKELY(x) x
#define RAPIDJSON_UNLIKELY(x) (x)
#endif
#endif
@ -530,6 +561,17 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
#endif
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1700)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
#else
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
#endif
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
//!@endcond
///////////////////////////////////////////////////////////////////////////////

View File

@ -19,6 +19,7 @@
#include "allocators.h"
#include "stream.h"
#include "encodedstream.h"
#include "internal/meta.h"
#include "internal/stack.h"
#include "internal/strtod.h"
@ -147,6 +148,7 @@ enum ParseFlag {
kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
};
@ -168,6 +170,8 @@ concept Handler {
bool Int64(int64_t i);
bool Uint64(uint64_t i);
bool Double(double d);
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
bool RawNumber(const Ch* str, SizeType length, bool copy);
bool String(const Ch* str, SizeType length, bool copy);
bool StartObject();
bool Key(const Ch* str, SizeType length, bool copy);
@ -198,6 +202,8 @@ struct BaseReaderHandler {
bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
bool Double(double) { return static_cast<Override&>(*this).Default(); }
/// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
bool StartObject() { return static_cast<Override&>(*this).Default(); }
bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
@ -259,6 +265,12 @@ void SkipWhitespace(InputStream& is) {
s.Take();
}
inline const char* SkipWhitespace(const char* p, const char* end) {
while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
return p;
}
#ifdef RAPIDJSON_SSE42
//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
inline const char *SkipWhitespace_SIMD(const char* p) {
@ -295,6 +307,34 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
}
}
inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
// Fast return for single non-whitespace
if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
else
return p;
// The middle of string using SIMD
static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
for (; p <= end - 16; p += 16) {
const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
if (r != 0) { // some of characters is non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset;
_BitScanForward(&offset, r);
return p + offset;
#else
return p + __builtin_ffs(r) - 1;
#endif
}
}
return SkipWhitespace(p, end);
}
#elif defined(RAPIDJSON_SSE2)
//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
@ -342,6 +382,44 @@ inline const char *SkipWhitespace_SIMD(const char* p) {
}
}
inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
// Fast return for single non-whitespace
if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
else
return p;
// The rest of string
#define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
#undef C16
const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
for (; p <= end - 16; p += 16) {
const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, w0);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
if (r != 0) { // some of characters may be non-whitespace
#ifdef _MSC_VER // Find the index of first non-whitespace
unsigned long offset;
_BitScanForward(&offset, r);
return p + offset;
#else
return p + __builtin_ffs(r) - 1;
#endif
}
}
return SkipWhitespace(p, end);
}
#endif // RAPIDJSON_SSE2
#ifdef RAPIDJSON_SIMD
@ -354,6 +432,10 @@ template<> inline void SkipWhitespace(InsituStringStream& is) {
template<> inline void SkipWhitespace(StringStream& is) {
is.src_ = SkipWhitespace_SIMD(is.src_);
}
template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
}
#endif // RAPIDJSON_SIMD
///////////////////////////////////////////////////////////////////////////////
@ -976,6 +1058,8 @@ private:
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
RAPIDJSON_FORCEINLINE void Push(char) {}
size_t Tell() { return is.Tell(); }
size_t Length() { return 0; }
const char* Pop() { return 0; }
@ -998,6 +1082,10 @@ private:
return Base::is.Take();
}
RAPIDJSON_FORCEINLINE void Push(char c) {
stackStream.Put(c);
}
size_t Length() { return stackStream.Length(); }
const char* Pop() {
@ -1012,7 +1100,11 @@ private:
template<unsigned parseFlags, typename InputStream, typename Handler>
void ParseNumber(InputStream& is, Handler& handler) {
internal::StreamLocalCopy<InputStream> copy(is);
NumberStream<InputStream, (parseFlags & kParseFullPrecisionFlag) != 0> s(*this, copy.s);
NumberStream<InputStream,
((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
((parseFlags & kParseInsituFlag) == 0) :
((parseFlags & kParseFullPrecisionFlag) != 0)> s(*this, copy.s);
size_t startOffset = s.Tell();
// Parse minus
@ -1099,6 +1191,9 @@ private:
int expFrac = 0;
size_t decimalPosition;
if (Consume(s, '.')) {
if (((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0)) {
s.Push('.');
}
decimalPosition = s.Length();
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
@ -1146,7 +1241,11 @@ private:
// Parse exp = e [ minus / plus ] 1*DIGIT
int exp = 0;
if (Consume(s, 'e') || Consume(s, 'E')) {
if (!useDouble) {
if ( ((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0) ) {
s.Push( 'e' );
}
if (!useDouble) {
d = static_cast<double>(use64bit ? i64 : i);
useDouble = true;
}
@ -1186,32 +1285,57 @@ private:
// Finish parsing, call event according to the type of number.
bool cont = true;
size_t length = s.Length();
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
if (useDouble) {
int p = exp + expFrac;
if (parseFlags & kParseFullPrecisionFlag)
d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
else
d = internal::StrtodNormalPrecision(d, p);
cont = handler.Double(minus ? -d : d);
}
else {
if (use64bit) {
if (minus)
cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
else
cont = handler.Uint64(i64);
if (parseFlags & kParseNumbersAsStringsFlag) {
if (parseFlags & kParseInsituFlag) {
s.Pop(); // Pop stack no matter if it will be used or not.
typename InputStream::Ch* head = is.PutBegin();
const size_t length = s.Tell() - startOffset;
RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
// unable to insert the \0 character here, it will erase the comma after this number
const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
cont = handler.RawNumber(str, SizeType(length), false);
}
else {
if (minus)
cont = handler.Int(static_cast<int32_t>(~i + 1));
else
cont = handler.Uint(i);
StackStream<typename TargetEncoding::Ch> stackStream(stack_);
SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
while (numCharsToCopy--) {
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, stackStream);
}
stackStream.Put('\0');
const typename TargetEncoding::Ch* str = stackStream.Pop();
const SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
cont = handler.RawNumber(str, SizeType(length), true);
}
}
else {
size_t length = s.Length();
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
if (useDouble) {
int p = exp + expFrac;
if (parseFlags & kParseFullPrecisionFlag)
d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
else
d = internal::StrtodNormalPrecision(d, p);
cont = handler.Double(minus ? -d : d);
}
else {
if (use64bit) {
if (minus)
cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
else
cont = handler.Uint64(i64);
}
else {
if (minus)
cont = handler.Int(static_cast<int32_t>(~i + 1));
else
cont = handler.Uint(i);
}
}
}
if (RAPIDJSON_UNLIKELY(!cont))
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
}

View File

@ -183,6 +183,11 @@ public:
return WriteNumber(n);
}
bool RawNumber(const Ch* str, SizeType len, bool) {
WriteBuffer(kNumberType, str, len * sizeof(Ch));
return true;
}
bool String(const Ch* str, SizeType len, bool) {
WriteBuffer(kStringType, str, len * sizeof(Ch));
return true;
@ -1322,7 +1327,7 @@ public:
\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
\param allocator An optional allocator instance for allocating memory. Can be null.
*/
GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) RAPIDJSON_NOEXCEPT :
remoteProvider_(remoteProvider),
allocator_(allocator),
ownAllocator_(),
@ -1357,6 +1362,22 @@ public:
schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
//! Move constructor in C++11
GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
remoteProvider_(rhs.remoteProvider_),
allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
root_(rhs.root_),
schemaMap_(std::move(rhs.schemaMap_)),
schemaRef_(std::move(rhs.schemaRef_))
{
rhs.remoteProvider_ = 0;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
}
#endif
//! Destructor
~GenericSchemaDocument() {
while (!schemaMap_.Empty())
@ -1369,6 +1390,11 @@ public:
const SchemaType& GetRoot() const { return *root_; }
private:
//! Prohibit copying
GenericSchemaDocument(const GenericSchemaDocument&);
//! Prohibit assignment
GenericSchemaDocument& operator=(const GenericSchemaDocument&);
struct SchemaRefEntry {
SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
PointerType source;
@ -1658,6 +1684,8 @@ RAPIDJSON_MULTILINEMACRO_END
bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
bool RawNumber(const Ch* str, SizeType length, bool copy)
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
bool String(const Ch* str, SizeType length, bool copy)
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }

View File

@ -23,6 +23,16 @@
#include "stringbuffer.h"
#include <new> // placement new
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h>
#pragma intrinsic(_BitScanForward)
#endif
#ifdef RAPIDJSON_SSE42
#include <nmmintrin.h>
#elif defined(RAPIDJSON_SSE2)
#include <emmintrin.h>
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
@ -171,6 +181,12 @@ public:
*/
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
Prefix(kNumberType);
return WriteString(str, length);
}
bool String(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
Prefix(kStringType);

View File

@ -10,6 +10,15 @@ 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

View File

@ -30,6 +30,8 @@
# define RAPIDJSON_SSE2
#endif
#define RAPIDJSON_HAS_STDSTRING 1
////////////////////////////////////////////////////////////////////////////////
// Google Test

View File

@ -187,6 +187,25 @@ TEST_F(RapidJson, SIMD_SUFFIX(DocumentParse_MemoryPoolAllocator)) {
}
}
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;

View File

@ -25,6 +25,15 @@ set(UNITTEST_SOURCES
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")

View File

@ -34,6 +34,8 @@ 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());
@ -93,6 +95,26 @@ void ParseTest() {
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) {
@ -140,6 +162,47 @@ static FILE* OpenEncodedFile(const char* filename) {
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");

View File

@ -81,6 +81,12 @@ TEST(dtoa, maxDecimalPlaces) {
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
}

View File

@ -1170,6 +1170,8 @@ struct IterativeParsingReaderHandler {
bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_DOUBLE; return true; }
bool RawNumber(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; }
bool String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; }
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
@ -1349,12 +1351,13 @@ struct TerminateHandler {
bool Int64(int64_t) { return e != 4; }
bool Uint64(uint64_t) { return e != 5; }
bool Double(double) { return e != 6; }
bool String(const char*, SizeType, bool) { return e != 7; }
bool StartObject() { return e != 8; }
bool Key(const char*, SizeType, bool) { return e != 9; }
bool EndObject(SizeType) { return e != 10; }
bool StartArray() { return e != 11; }
bool EndArray(SizeType) { return e != 12; }
bool RawNumber(const char*, SizeType, bool) { return e != 7; }
bool String(const char*, SizeType, bool) { return e != 8; }
bool StartObject() { return e != 9; }
bool Key(const char*, SizeType, bool) { return e != 10; }
bool EndObject(SizeType) { return e != 11; }
bool StartArray() { return e != 12; }
bool EndArray(SizeType) { return e != 13; }
};
#define TEST_TERMINATION(e, json)\
@ -1375,14 +1378,15 @@ TEST(Reader, ParseTerminationByHandler) {
TEST_TERMINATION(4, "[-1234567890123456789");
TEST_TERMINATION(5, "[1234567890123456789");
TEST_TERMINATION(6, "[0.5]");
TEST_TERMINATION(7, "[\"a\"");
TEST_TERMINATION(8, "[{");
TEST_TERMINATION(9, "[{\"a\"");
TEST_TERMINATION(10, "[{}");
TEST_TERMINATION(10, "[{\"a\":1}"); // non-empty object
TEST_TERMINATION(11, "{\"a\":[");
TEST_TERMINATION(12, "{\"a\":[]");
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
// RawNumber() is never called
TEST_TERMINATION(8, "[\"a\"");
TEST_TERMINATION(9, "[{");
TEST_TERMINATION(10, "[{\"a\"");
TEST_TERMINATION(11, "[{}");
TEST_TERMINATION(11, "[{\"a\":1}"); // non-empty object
TEST_TERMINATION(12, "{\"a\":[");
TEST_TERMINATION(13, "{\"a\":[]");
TEST_TERMINATION(13, "{\"a\":[1]"); // non-empty array
}
TEST(Reader, ParseComments) {
@ -1508,6 +1512,46 @@ TEST(Reader, UnrecognizedComment) {
EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
}
struct NumbersAsStringsHandler {
bool Null() { return true; }
bool Bool(bool) { return true; }
bool Int(int) { return true; }
bool Uint(unsigned) { return true; }
bool Int64(int64_t) { return true; }
bool Uint64(uint64_t) { return true; }
bool Double(double) { return true; }
// 'str' is not null-terminated
bool RawNumber(const char* str, SizeType length, bool) {
EXPECT_TRUE(str != 0);
EXPECT_TRUE(strncmp(str, "3.1416", length) == 0);
return true;
}
bool String(const char*, SizeType, bool) { return true; }
bool StartObject() { return true; }
bool Key(const char*, SizeType, bool) { return true; }
bool EndObject(SizeType) { return true; }
bool StartArray() { return true; }
bool EndArray(SizeType) { return true; }
};
TEST(Reader, NumbersAsStrings) {
{
const char* json = "{ \"pi\": 3.1416 } ";
StringStream s(json);
NumbersAsStringsHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<kParseNumbersAsStringsFlag>(s, h));
}
{
char* json = StrDup("{ \"pi\": 3.1416 } ");
InsituStringStream s(json);
NumbersAsStringsHandler h;
Reader reader;
EXPECT_TRUE(reader.Parse<kParseInsituFlag|kParseNumbersAsStringsFlag>(s, h));
free(json);
}
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif

View File

@ -1152,6 +1152,24 @@ TEST(SchemaValidatingWriter, Simple) {
EXPECT_TRUE(validator.GetInvalidDocumentPointer() == SchemaDocument::PointerType(""));
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
static SchemaDocument ReturnSchemaDocument() {
Document sd;
sd.Parse("{ \"type\": [\"number\", \"string\"] }");
SchemaDocument s(sd);
return s;
}
TEST(Schema, Issue552) {
SchemaDocument s = ReturnSchemaDocument();
VALIDATE(s, "42", true);
VALIDATE(s, "\"Life, the universe, and everything\"", true);
INVALIDATE(s, "[\"Life\", \"the universe\", \"and everything\"]", "", "type", "");
}
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif

View File

@ -73,6 +73,28 @@ TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
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);

View File

@ -23,6 +23,18 @@ RAPIDJSON_DIAG_OFF(c++98-compat)
using namespace rapidjson;
TEST(Value, Size) {
if (sizeof(SizeType) == 4) {
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
EXPECT_EQ(16, sizeof(Value));
#elif RAPIDJSON_64BIT
EXPECT_EQ(24, sizeof(Value));
#else
EXPECT_EQ(16, sizeof(Value));
#endif
}
}
TEST(Value, DefaultConstructor) {
Value x;
EXPECT_EQ(kNullType, x.GetType());
@ -335,6 +347,12 @@ TEST(Value, True) {
Value z;
z.SetBool(true);
EXPECT_TRUE(z.IsTrue());
// Templated functions
EXPECT_TRUE(z.Is<bool>());
EXPECT_TRUE(z.Get<bool>());
EXPECT_FALSE(z.Set<bool>(false).Get<bool>());
EXPECT_TRUE(z.Set(true).Get<bool>());
}
TEST(Value, False) {
@ -414,6 +432,12 @@ TEST(Value, Int) {
// operator=(int)
z = 5678;
EXPECT_EQ(5678, z.GetInt());
// Templated functions
EXPECT_TRUE(z.Is<int>());
EXPECT_EQ(5678, z.Get<int>());
EXPECT_EQ(5679, z.Set(5679).Get<int>());
EXPECT_EQ(5680, z.Set<int>(5680).Get<int>());
}
TEST(Value, Uint) {
@ -453,6 +477,12 @@ TEST(Value, Uint) {
EXPECT_EQ(2147483648u, z.GetUint());
EXPECT_FALSE(z.IsInt());
EXPECT_TRUE(z.IsInt64()); // Issue 41: Incorrect parsing of unsigned int number types
// Templated functions
EXPECT_TRUE(z.Is<unsigned>());
EXPECT_EQ(2147483648u, z.Get<unsigned>());
EXPECT_EQ(2147483649u, z.Set(2147483649u).Get<unsigned>());
EXPECT_EQ(2147483650u, z.Set<unsigned>(2147483650u).Get<unsigned>());
}
TEST(Value, Int64) {
@ -505,8 +535,15 @@ TEST(Value, Int64) {
EXPECT_FALSE(z.IsInt());
EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0);
z.SetInt64(static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000)));
int64_t i = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000));
z.SetInt64(i);
EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble());
// Templated functions
EXPECT_TRUE(z.Is<int64_t>());
EXPECT_EQ(i, z.Get<int64_t>());
EXPECT_EQ(i - 1, z.Set(i - 1).Get<int64_t>());
EXPECT_EQ(i - 2, z.Set<int64_t>(i - 2).Get<int64_t>());
}
TEST(Value, Uint64) {
@ -547,10 +584,17 @@ TEST(Value, Uint64) {
EXPECT_FALSE(z.IsUint());
EXPECT_TRUE(z.IsInt64());
z.SetUint64(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)); // 2^63 cannot cast as int64
uint64_t u = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
z.SetUint64(u); // 2^63 cannot cast as int64
EXPECT_FALSE(z.IsInt64());
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000), z.GetUint64()); // Issue 48
EXPECT_EQ(u, z.GetUint64()); // Issue 48
EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble());
// Templated functions
EXPECT_TRUE(z.Is<uint64_t>());
EXPECT_EQ(u, z.Get<uint64_t>());
EXPECT_EQ(u + 1, z.Set(u + 1).Get<uint64_t>());
EXPECT_EQ(u + 2, z.Set<uint64_t>(u + 2).Get<uint64_t>());
}
TEST(Value, Double) {
@ -577,6 +621,12 @@ TEST(Value, Double) {
z = 56.78;
EXPECT_NEAR(56.78, z.GetDouble(), 0.0);
// Templated functions
EXPECT_TRUE(z.Is<double>());
EXPECT_EQ(56.78, z.Get<double>());
EXPECT_EQ(57.78, z.Set(57.78).Get<double>());
EXPECT_EQ(58.78, z.Set<double>(58.78).Get<double>());
}
TEST(Value, Float) {
@ -602,18 +652,30 @@ TEST(Value, Float) {
z.SetFloat(12.34f);
EXPECT_NEAR(12.34f, z.GetFloat(), 0.0f);
// Issue 573
z.SetInt(0);
EXPECT_EQ(0.0f, z.GetFloat());
z = 56.78f;
EXPECT_NEAR(56.78f, z.GetFloat(), 0.0f);
// Templated functions
EXPECT_TRUE(z.Is<float>());
EXPECT_EQ(56.78f, z.Get<float>());
EXPECT_EQ(57.78f, z.Set(57.78f).Get<float>());
EXPECT_EQ(58.78f, z.Set<float>(58.78f).Get<float>());
}
TEST(Value, IsLosslessDouble) {
EXPECT_TRUE(Value(12.34).IsLosslessDouble());
EXPECT_TRUE(Value(-123).IsLosslessDouble());
EXPECT_TRUE(Value(2147483648u).IsLosslessDouble());
EXPECT_TRUE(Value(static_cast<int64_t>(-RAPIDJSON_UINT64_C2(0x40000000, 0x00000000))).IsLosslessDouble());
EXPECT_TRUE(Value(-static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x40000000, 0x00000000))).IsLosslessDouble());
#if !(defined(_MSC_VER) && _MSC_VER < 1800) // VC2010 has problem
EXPECT_TRUE(Value(RAPIDJSON_UINT64_C2(0xA0000000, 0x00000000)).IsLosslessDouble());
#endif
EXPECT_FALSE(Value(static_cast<int64_t>(-RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble());
EXPECT_FALSE(Value(-static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x7FFFFFFF, 0xFFFFFFFF))).IsLosslessDouble());
EXPECT_FALSE(Value(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0xFFFFFFFF)).IsLosslessDouble());
}
@ -724,6 +786,11 @@ TEST(Value, String) {
EXPECT_STREQ("World", w.GetString());
EXPECT_EQ(5u, w.GetStringLength());
// templated functions
EXPECT_TRUE(z.Is<const char*>());
EXPECT_STREQ(cstr, z.Get<const char*>());
EXPECT_STREQ("Apple", z.Set<const char*>("Apple").Get<const char*>());
#if RAPIDJSON_HAS_STDSTRING
{
std::string str = "Hello World";
@ -759,6 +826,14 @@ TEST(Value, String) {
vs1 = StringRef(str);
TestEqual(str, vs1);
TestEqual(vs0, vs1);
// Templated function.
EXPECT_TRUE(vs0.Is<std::string>());
EXPECT_EQ(str, vs0.Get<std::string>());
vs0.Set<std::string>(std::string("Apple"), allocator);
EXPECT_EQ(std::string("Apple"), vs0.Get<std::string>());
vs0.Set(std::string("Orange"), allocator);
EXPECT_EQ(std::string("Orange"), vs0.Get<std::string>());
}
#endif // RAPIDJSON_HAS_STDSTRING
}
@ -769,25 +844,9 @@ TEST(Value, SetStringNullException) {
EXPECT_THROW(v.SetString(0, 0), AssertException);
}
TEST(Value, Array) {
Value x(kArrayType);
const Value& y = x;
Value::AllocatorType allocator;
EXPECT_EQ(kArrayType, x.GetType());
EXPECT_TRUE(x.IsArray());
EXPECT_TRUE(x.Empty());
EXPECT_EQ(0u, x.Size());
EXPECT_TRUE(y.IsArray());
EXPECT_TRUE(y.Empty());
EXPECT_EQ(0u, y.Size());
EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse());
EXPECT_FALSE(x.IsTrue());
EXPECT_FALSE(x.IsString());
EXPECT_FALSE(x.IsObject());
template <typename T, typename Allocator>
static void TestArray(T& x, Allocator& allocator) {
const T& y = x;
// PushBack()
Value v;
@ -834,7 +893,7 @@ TEST(Value, Array) {
#endif
// iterator
Value::ValueIterator itr = x.Begin();
typename T::ValueIterator itr = x.Begin();
EXPECT_TRUE(itr != x.End());
EXPECT_TRUE(itr->IsNull());
++itr;
@ -853,7 +912,7 @@ TEST(Value, Array) {
EXPECT_STREQ("foo", itr->GetString());
// const iterator
Value::ConstValueIterator citr = y.Begin();
typename T::ConstValueIterator citr = y.Begin();
EXPECT_TRUE(citr != y.End());
EXPECT_TRUE(citr->IsNull());
++citr;
@ -939,6 +998,29 @@ TEST(Value, Array) {
EXPECT_EQ(i + removeCount, x[static_cast<SizeType>(i)][0].GetUint());
}
}
}
TEST(Value, Array) {
Value x(kArrayType);
const Value& y = x;
Value::AllocatorType allocator;
EXPECT_EQ(kArrayType, x.GetType());
EXPECT_TRUE(x.IsArray());
EXPECT_TRUE(x.Empty());
EXPECT_EQ(0u, x.Size());
EXPECT_TRUE(y.IsArray());
EXPECT_TRUE(y.Empty());
EXPECT_EQ(0u, y.Size());
EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse());
EXPECT_FALSE(x.IsTrue());
EXPECT_FALSE(x.IsString());
EXPECT_FALSE(x.IsObject());
TestArray(x, allocator);
// Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed.
// http://en.wikipedia.org/wiki/Erase-remove_idiom
@ -962,19 +1044,96 @@ TEST(Value, Array) {
EXPECT_TRUE(z.Empty());
}
TEST(Value, Object) {
Value x(kObjectType);
const Value& y = x; // const version
TEST(Value, ArrayHelper) {
Value::AllocatorType allocator;
{
Value x(kArrayType);
Value::Array a = x.GetArray();
TestArray(a, allocator);
}
EXPECT_EQ(kObjectType, x.GetType());
EXPECT_TRUE(x.IsObject());
EXPECT_TRUE(x.ObjectEmpty());
EXPECT_EQ(0u, x.MemberCount());
EXPECT_EQ(kObjectType, y.GetType());
EXPECT_TRUE(y.IsObject());
EXPECT_TRUE(y.ObjectEmpty());
EXPECT_EQ(0u, y.MemberCount());
{
Value x(kArrayType);
Value::Array a = x.GetArray();
a.PushBack(1, allocator);
Value::Array a2(a); // copy constructor
EXPECT_EQ(1, a2.Size());
Value::Array a3 = a;
EXPECT_EQ(1, a3.Size());
Value::ConstArray y = static_cast<const Value&>(x).GetArray();
(void)y;
// y.PushBack(1, allocator); // should not compile
// Templated functions
x.Clear();
EXPECT_TRUE(x.Is<Value::Array>());
EXPECT_TRUE(x.Is<Value::ConstArray>());
a.PushBack(1, allocator);
EXPECT_EQ(1, x.Get<Value::Array>()[0].GetInt());
EXPECT_EQ(1, x.Get<Value::ConstArray>()[0].GetInt());
Value x2;
x2.Set<Value::Array>(a);
EXPECT_TRUE(x.IsArray()); // IsArray() is invariant after moving.
EXPECT_EQ(1, x2.Get<Value::Array>()[0].GetInt());
}
{
Value y(kArrayType);
y.PushBack(123, allocator);
Value x(y.GetArray()); // Construct value form array.
EXPECT_TRUE(x.IsArray());
EXPECT_EQ(123, x[0].GetInt());
EXPECT_TRUE(y.IsArray()); // Invariant
EXPECT_TRUE(y.Empty());
}
{
Value x(kArrayType);
Value y(kArrayType);
y.PushBack(123, allocator);
x.PushBack(y.GetArray(), allocator); // Implicit constructor to convert Array to GenericValue
EXPECT_EQ(1, x.Size());
EXPECT_EQ(123, x[0][0].GetInt());
EXPECT_TRUE(y.IsArray());
EXPECT_TRUE(y.Empty());
}
}
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
TEST(Value, ArrayHelperRangeFor) {
Value::AllocatorType allocator;
Value x(kArrayType);
for (int i = 0; i < 10; i++)
x.PushBack(i, allocator);
{
int i = 0;
for (auto& v : x.GetArray())
EXPECT_EQ(i++, v.GetInt());
EXPECT_EQ(i, 10);
}
{
int i = 0;
for (const auto& v : const_cast<const Value&>(x).GetArray())
EXPECT_EQ(i++, v.GetInt());
EXPECT_EQ(i, 10);
}
// Array a = x.GetArray();
// Array ca = const_cast<const Value&>(x).GetArray();
}
#endif
template <typename T, typename Allocator>
static void TestObject(T& x, Allocator& allocator) {
const T& y = x; // const version
// AddMember()
x.AddMember("A", "Apple", allocator);
@ -1215,7 +1374,7 @@ TEST(Value, Object) {
const unsigned n = 10;
for (unsigned first = 0; first < n; first++) {
for (unsigned last = first; last <= n; last++) {
Value(kObjectType).Swap(x);
x.RemoveAllMembers();
for (unsigned i = 0; i < n; i++)
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
@ -1238,6 +1397,23 @@ TEST(Value, Object) {
x.RemoveAllMembers();
EXPECT_TRUE(x.ObjectEmpty());
EXPECT_EQ(0u, x.MemberCount());
}
TEST(Value, Object) {
Value x(kObjectType);
const Value& y = x; // const version
Value::AllocatorType allocator;
EXPECT_EQ(kObjectType, x.GetType());
EXPECT_TRUE(x.IsObject());
EXPECT_TRUE(x.ObjectEmpty());
EXPECT_EQ(0u, x.MemberCount());
EXPECT_EQ(kObjectType, y.GetType());
EXPECT_TRUE(y.IsObject());
EXPECT_TRUE(y.ObjectEmpty());
EXPECT_EQ(0u, y.MemberCount());
TestObject(x, allocator);
// SetObject()
Value z;
@ -1245,6 +1421,100 @@ TEST(Value, Object) {
EXPECT_TRUE(z.IsObject());
}
TEST(Value, ObjectHelper) {
Value::AllocatorType allocator;
{
Value x(kObjectType);
Value::Object o = x.GetObject();
TestObject(o, allocator);
}
{
Value x(kObjectType);
Value::Object o = x.GetObject();
o.AddMember("1", 1, allocator);
Value::Object o2(o); // copy constructor
EXPECT_EQ(1, o2.MemberCount());
Value::Object o3 = o;
EXPECT_EQ(1, o3.MemberCount());
Value::ConstObject y = static_cast<const Value&>(x).GetObject();
(void)y;
// y.AddMember("1", 1, allocator); // should not compile
// Templated functions
x.RemoveAllMembers();
EXPECT_TRUE(x.Is<Value::Object>());
EXPECT_TRUE(x.Is<Value::ConstObject>());
o.AddMember("1", 1, allocator);
EXPECT_EQ(1, x.Get<Value::Object>()["1"].GetInt());
EXPECT_EQ(1, x.Get<Value::ConstObject>()["1"].GetInt());
Value x2;
x2.Set<Value::Object>(o);
EXPECT_TRUE(x.IsObject()); // IsObject() is invariant after moving
EXPECT_EQ(1, x2.Get<Value::Object>()["1"].GetInt());
}
{
Value x(kObjectType);
x.AddMember("a", "apple", allocator);
Value y(x.GetObject());
EXPECT_STREQ("apple", y["a"].GetString());
EXPECT_TRUE(x.IsObject()); // Invariant
}
{
Value x(kObjectType);
x.AddMember("a", "apple", allocator);
Value y(kObjectType);
y.AddMember("fruits", x.GetObject(), allocator);
EXPECT_STREQ("apple", y["fruits"]["a"].GetString());
EXPECT_TRUE(x.IsObject()); // Invariant
}
}
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
TEST(Value, ObjectHelperRangeFor) {
Value::AllocatorType allocator;
Value x(kObjectType);
for (int i = 0; i < 10; i++) {
char name[10];
Value n(name, static_cast<SizeType>(sprintf(name, "%d", i)), allocator);
x.AddMember(n, i, allocator);
}
{
int i = 0;
for (auto& m : x.GetObject()) {
char name[10];
sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt());
i++;
}
EXPECT_EQ(i, 10);
}
{
int i = 0;
for (const auto& m : const_cast<const Value&>(x).GetObject()) {
char name[10];
sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt());
i++;
}
EXPECT_EQ(i, 10);
}
// Object a = x.GetObject();
// Object ca = const_cast<const Value&>(x).GetObject();
}
#endif
TEST(Value, EraseMember_String) {
Value::AllocatorType allocator;
Value x(kObjectType);
@ -1378,12 +1648,13 @@ struct TerminateHandler {
bool Int64(int64_t) { return e != 4; }
bool Uint64(uint64_t) { return e != 5; }
bool Double(double) { return e != 6; }
bool String(const char*, SizeType, bool) { return e != 7; }
bool StartObject() { return e != 8; }
bool Key(const char*, SizeType, bool) { return e != 9; }
bool EndObject(SizeType) { return e != 10; }
bool StartArray() { return e != 11; }
bool EndArray(SizeType) { return e != 12; }
bool RawNumber(const char*, SizeType, bool) { return e != 7; }
bool String(const char*, SizeType, bool) { return e != 8; }
bool StartObject() { return e != 9; }
bool Key(const char*, SizeType, bool) { return e != 10; }
bool EndObject(SizeType) { return e != 11; }
bool StartArray() { return e != 12; }
bool EndArray(SizeType) { return e != 13; }
};
#define TEST_TERMINATION(e, json)\
@ -1404,12 +1675,13 @@ TEST(Value, AcceptTerminationByHandler) {
TEST_TERMINATION(4, "[-1234567890123456789]");
TEST_TERMINATION(5, "[9223372036854775808]");
TEST_TERMINATION(6, "[0.5]");
TEST_TERMINATION(7, "[\"a\"]");
TEST_TERMINATION(8, "[{}]");
TEST_TERMINATION(9, "[{\"a\":1}]");
TEST_TERMINATION(10, "[{}]");
TEST_TERMINATION(11, "{\"a\":[]}");
// RawNumber() is never called
TEST_TERMINATION(8, "[\"a\"]");
TEST_TERMINATION(9, "[{}]");
TEST_TERMINATION(10, "[{\"a\":1}]");
TEST_TERMINATION(11, "[{}]");
TEST_TERMINATION(12, "{\"a\":[]}");
TEST_TERMINATION(13, "{\"a\":[]}");
}
struct ValueIntComparer {