Merge branch 'master' into travis
This commit is contained in:
commit
031a0b6660
22
.gitattributes
vendored
Normal file
22
.gitattributes
vendored
Normal 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
|
37
.travis.yml
37
.travis.yml
@ -48,32 +48,68 @@ matrix:
|
|||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
|
sources:
|
||||||
|
- llvm-toolchain-precise-3.7
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- *default_packages
|
- *default_packages
|
||||||
- g++-multilib
|
- g++-multilib
|
||||||
- libc6-dbg:i386
|
- libc6-dbg:i386
|
||||||
|
- clang-3.7
|
||||||
- env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
|
- env: CONF=debug ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
|
||||||
compiler: clang
|
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
|
- env: CONF=debug ARCH=x86 CXX11=OFF CCACHE_CPP2=yes
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
|
sources:
|
||||||
|
- llvm-toolchain-precise-3.7
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- *default_packages
|
- *default_packages
|
||||||
- g++-multilib
|
- g++-multilib
|
||||||
- libc6-dbg:i386
|
- libc6-dbg:i386
|
||||||
|
- clang-3.7
|
||||||
- env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes
|
- env: CONF=debug ARCH=x86_64 CXX11=OFF CCACHE_CPP2=yes
|
||||||
compiler: clang
|
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
|
- env: CONF=release ARCH=x86 CXX11=ON CCACHE_CPP2=yes
|
||||||
compiler: clang
|
compiler: clang
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
|
sources:
|
||||||
|
- llvm-toolchain-precise-3.7
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
packages:
|
packages:
|
||||||
- *default_packages
|
- *default_packages
|
||||||
- g++-multilib
|
- g++-multilib
|
||||||
- libc6-dbg:i386
|
- libc6-dbg:i386
|
||||||
|
- clang-3.7
|
||||||
- env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
|
- env: CONF=release ARCH=x86_64 CXX11=ON CCACHE_CPP2=yes
|
||||||
compiler: clang
|
compiler: clang
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- llvm-toolchain-precise-3.7
|
||||||
|
- ubuntu-toolchain-r-test
|
||||||
|
packages:
|
||||||
|
- *default_packages
|
||||||
|
- clang-3.7
|
||||||
# coverage report
|
# coverage report
|
||||||
- env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage'
|
- env: CONF=debug ARCH=x86 CXX11=ON GCOV_FLAGS='--coverage'
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
@ -122,6 +158,7 @@ before_script:
|
|||||||
- mkdir build
|
- mkdir build
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
- if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi
|
||||||
- >
|
- >
|
||||||
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
|
eval "ARCH_FLAGS=\${ARCH_FLAGS_${ARCH}}" ;
|
||||||
(cd build && cmake
|
(cd build && cmake
|
||||||
|
8
docker/debian/Dockerfile
Normal file
8
docker/debian/Dockerfile
Normal 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"]
|
@ -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)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
set(EXAMPLES
|
set(EXAMPLES
|
||||||
@ -8,6 +5,7 @@ set(EXAMPLES
|
|||||||
condense
|
condense
|
||||||
jsonx
|
jsonx
|
||||||
messagereader
|
messagereader
|
||||||
|
parsebyparts
|
||||||
pretty
|
pretty
|
||||||
prettyauto
|
prettyauto
|
||||||
schemavalidator
|
schemavalidator
|
||||||
@ -22,9 +20,9 @@ include_directories("../include/")
|
|||||||
add_definitions(-D__STDC_FORMAT_MACROS)
|
add_definitions(-D__STDC_FORMAT_MACROS)
|
||||||
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
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")
|
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")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lpthread -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS=1)
|
||||||
endif()
|
endif()
|
||||||
|
@ -24,6 +24,7 @@ struct CapitalizeFilter {
|
|||||||
bool Int64(int64_t i) { return out_.Int64(i); }
|
bool Int64(int64_t i) { return out_.Int64(i); }
|
||||||
bool Uint64(uint64_t u) { return out_.Uint64(u); }
|
bool Uint64(uint64_t u) { return out_.Uint64(u); }
|
||||||
bool Double(double d) { return out_.Double(d); }
|
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) {
|
bool String(const char* str, SizeType length, bool) {
|
||||||
buffer_.clear();
|
buffer_.clear();
|
||||||
for (SizeType i = 0; i < length; i++)
|
for (SizeType i = 0; i < length; i++)
|
||||||
|
@ -57,6 +57,13 @@ public:
|
|||||||
return WriteNumberElement(buffer, sprintf(buffer, "%.17g", d));
|
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) {
|
bool String(const char* str, SizeType length, bool) {
|
||||||
return
|
return
|
||||||
WriteStartElement("string") &&
|
WriteStartElement("string") &&
|
||||||
|
172
example/parsebyparts/parsebyparts.cpp
Normal file
172
example/parsebyparts/parsebyparts.cpp
Normal 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
|
@ -12,6 +12,10 @@ struct MyHandler {
|
|||||||
bool Int64(int64_t i) { cout << "Int64(" << i << ")" << 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 Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
|
||||||
bool Double(double d) { cout << "Double(" << d << ")" << 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) {
|
bool String(const char* str, SizeType length, bool copy) {
|
||||||
cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
|
cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
|
||||||
return true;
|
return true;
|
||||||
|
@ -2325,6 +2325,14 @@ public:
|
|||||||
bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
|
bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
|
||||||
bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
|
bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
|
||||||
|
|
||||||
|
bool RawNumber(const Ch* str, SizeType length, bool copy) {
|
||||||
|
if (copy)
|
||||||
|
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
|
||||||
|
else
|
||||||
|
new (stack_.template Push<ValueType>()) ValueType(str, length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool String(const Ch* str, SizeType length, bool copy) {
|
bool String(const Ch* str, SizeType length, bool copy) {
|
||||||
if (copy)
|
if (copy)
|
||||||
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
|
new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
|
||||||
|
@ -29,6 +29,7 @@ namespace internal {
|
|||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
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
|
#endif
|
||||||
|
|
||||||
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
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) {
|
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
|
||||||
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||||
|
|
||||||
if (length <= kk && kk <= 21) {
|
if (0 <= k && kk <= 21) {
|
||||||
// 1234e7 -> 12340000000
|
// 1234e7 -> 12340000000
|
||||||
for (int i = length; i < kk; i++)
|
for (int i = length; i < kk; i++)
|
||||||
buffer[i] = '0';
|
buffer[i] = '0';
|
||||||
@ -160,7 +161,7 @@ inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
|
|||||||
// 1234e-2 -> 12.34
|
// 1234e-2 -> 12.34
|
||||||
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||||
buffer[kk] = '.';
|
buffer[kk] = '.';
|
||||||
if (length > kk + maxDecimalPlaces) {
|
if (0 > k + maxDecimalPlaces) {
|
||||||
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
|
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
|
||||||
// Remove extra trailing zeros (at least one) after truncation.
|
// Remove extra trailing zeros (at least one) after truncation.
|
||||||
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
|
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
|
||||||
|
@ -74,6 +74,12 @@ public:
|
|||||||
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
||||||
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
|
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) {
|
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||||
(void)copy;
|
(void)copy;
|
||||||
PrettyPrefix(kStringType);
|
PrettyPrefix(kStringType);
|
||||||
|
@ -159,7 +159,7 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef RAPIDJSON_NO_INT64DEFINE
|
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||||
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
#ifdef _MSC_VER
|
#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
|
||||||
#include "msinttypes/stdint.h"
|
#include "msinttypes/stdint.h"
|
||||||
#include "msinttypes/inttypes.h"
|
#include "msinttypes/inttypes.h"
|
||||||
#else
|
#else
|
||||||
@ -452,7 +452,7 @@ RAPIDJSON_NAMESPACE_END
|
|||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
|
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_LIKELY(x) x
|
#define RAPIDJSON_LIKELY(x) (x)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -465,7 +465,7 @@ RAPIDJSON_NAMESPACE_END
|
|||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_UNLIKELY(x) x
|
#define RAPIDJSON_UNLIKELY(x) (x)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -148,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.
|
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).
|
kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
|
||||||
kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
|
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
|
kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -169,6 +170,8 @@ concept Handler {
|
|||||||
bool Int64(int64_t i);
|
bool Int64(int64_t i);
|
||||||
bool Uint64(uint64_t i);
|
bool Uint64(uint64_t i);
|
||||||
bool Double(double d);
|
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 String(const Ch* str, SizeType length, bool copy);
|
||||||
bool StartObject();
|
bool StartObject();
|
||||||
bool Key(const Ch* str, SizeType length, bool copy);
|
bool Key(const Ch* str, SizeType length, bool copy);
|
||||||
@ -199,6 +202,8 @@ struct BaseReaderHandler {
|
|||||||
bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
|
bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
|
||||||
bool Uint64(uint64_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(); }
|
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 String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
|
||||||
bool StartObject() { 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); }
|
bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
|
||||||
@ -1053,6 +1058,8 @@ private:
|
|||||||
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
|
RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
|
||||||
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
|
RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
|
||||||
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
|
RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
|
||||||
|
RAPIDJSON_FORCEINLINE void Push(char) {}
|
||||||
|
|
||||||
size_t Tell() { return is.Tell(); }
|
size_t Tell() { return is.Tell(); }
|
||||||
size_t Length() { return 0; }
|
size_t Length() { return 0; }
|
||||||
const char* Pop() { return 0; }
|
const char* Pop() { return 0; }
|
||||||
@ -1075,6 +1082,10 @@ private:
|
|||||||
return Base::is.Take();
|
return Base::is.Take();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_FORCEINLINE void Push(char c) {
|
||||||
|
stackStream.Put(c);
|
||||||
|
}
|
||||||
|
|
||||||
size_t Length() { return stackStream.Length(); }
|
size_t Length() { return stackStream.Length(); }
|
||||||
|
|
||||||
const char* Pop() {
|
const char* Pop() {
|
||||||
@ -1089,7 +1100,11 @@ private:
|
|||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseNumber(InputStream& is, Handler& handler) {
|
void ParseNumber(InputStream& is, Handler& handler) {
|
||||||
internal::StreamLocalCopy<InputStream> copy(is);
|
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();
|
size_t startOffset = s.Tell();
|
||||||
|
|
||||||
// Parse minus
|
// Parse minus
|
||||||
@ -1176,6 +1191,9 @@ private:
|
|||||||
int expFrac = 0;
|
int expFrac = 0;
|
||||||
size_t decimalPosition;
|
size_t decimalPosition;
|
||||||
if (Consume(s, '.')) {
|
if (Consume(s, '.')) {
|
||||||
|
if (((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0)) {
|
||||||
|
s.Push('.');
|
||||||
|
}
|
||||||
decimalPosition = s.Length();
|
decimalPosition = s.Length();
|
||||||
|
|
||||||
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
|
if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
|
||||||
@ -1223,6 +1241,10 @@ private:
|
|||||||
// Parse exp = e [ minus / plus ] 1*DIGIT
|
// Parse exp = e [ minus / plus ] 1*DIGIT
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
if (Consume(s, 'e') || Consume(s, 'E')) {
|
if (Consume(s, 'e') || Consume(s, 'E')) {
|
||||||
|
if ( ((parseFlags & kParseNumbersAsStringsFlag) != 0) && ((parseFlags & kParseInsituFlag) == 0) ) {
|
||||||
|
s.Push( 'e' );
|
||||||
|
}
|
||||||
|
|
||||||
if (!useDouble) {
|
if (!useDouble) {
|
||||||
d = static_cast<double>(use64bit ? i64 : i);
|
d = static_cast<double>(use64bit ? i64 : i);
|
||||||
useDouble = true;
|
useDouble = true;
|
||||||
@ -1263,6 +1285,32 @@ private:
|
|||||||
|
|
||||||
// Finish parsing, call event according to the type of number.
|
// Finish parsing, call event according to the type of number.
|
||||||
bool cont = true;
|
bool cont = true;
|
||||||
|
|
||||||
|
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);
|
||||||
|
// *(head + length) = '\0';
|
||||||
|
const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
|
||||||
|
cont = handler.RawNumber(str, SizeType(length), false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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();
|
size_t length = s.Length();
|
||||||
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
|
const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
|
||||||
|
|
||||||
@ -1289,6 +1337,7 @@ private:
|
|||||||
cont = handler.Uint(i);
|
cont = handler.Uint(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (RAPIDJSON_UNLIKELY(!cont))
|
if (RAPIDJSON_UNLIKELY(!cont))
|
||||||
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
|
RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,11 @@ public:
|
|||||||
return WriteNumber(n);
|
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) {
|
bool String(const Ch* str, SizeType len, bool) {
|
||||||
WriteBuffer(kStringType, str, len * sizeof(Ch));
|
WriteBuffer(kStringType, str, len * sizeof(Ch));
|
||||||
return true;
|
return true;
|
||||||
@ -1679,6 +1684,8 @@ RAPIDJSON_MULTILINEMACRO_END
|
|||||||
bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
|
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 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 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)
|
bool String(const Ch* str, SizeType length, bool copy)
|
||||||
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
|
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
|
||||||
|
|
||||||
|
@ -23,6 +23,16 @@
|
|||||||
#include "stringbuffer.h"
|
#include "stringbuffer.h"
|
||||||
#include <new> // placement new
|
#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
|
#ifdef _MSC_VER
|
||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||||
@ -171,6 +181,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
|
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) {
|
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||||
(void)copy;
|
(void)copy;
|
||||||
Prefix(kStringType);
|
Prefix(kStringType);
|
||||||
|
@ -1170,6 +1170,8 @@ struct IterativeParsingReaderHandler {
|
|||||||
|
|
||||||
bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_DOUBLE; return true; }
|
bool Double(double) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_DOUBLE; return true; }
|
||||||
|
|
||||||
|
bool 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 String(const Ch*, SizeType, bool) { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STRING; return true; }
|
||||||
|
|
||||||
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
|
bool StartObject() { RAPIDJSON_ASSERT(LogCount < LogCapacity); Logs[LogCount++] = LOG_STARTOBJECT; return true; }
|
||||||
@ -1349,12 +1351,13 @@ struct TerminateHandler {
|
|||||||
bool Int64(int64_t) { return e != 4; }
|
bool Int64(int64_t) { return e != 4; }
|
||||||
bool Uint64(uint64_t) { return e != 5; }
|
bool Uint64(uint64_t) { return e != 5; }
|
||||||
bool Double(double) { return e != 6; }
|
bool Double(double) { return e != 6; }
|
||||||
bool String(const char*, SizeType, bool) { return e != 7; }
|
bool RawNumber(const char*, SizeType, bool) { return e != 7; }
|
||||||
bool StartObject() { return e != 8; }
|
bool String(const char*, SizeType, bool) { return e != 8; }
|
||||||
bool Key(const char*, SizeType, bool) { return e != 9; }
|
bool StartObject() { return e != 9; }
|
||||||
bool EndObject(SizeType) { return e != 10; }
|
bool Key(const char*, SizeType, bool) { return e != 10; }
|
||||||
bool StartArray() { return e != 11; }
|
bool EndObject(SizeType) { return e != 11; }
|
||||||
bool EndArray(SizeType) { return e != 12; }
|
bool StartArray() { return e != 12; }
|
||||||
|
bool EndArray(SizeType) { return e != 13; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TEST_TERMINATION(e, json)\
|
#define TEST_TERMINATION(e, json)\
|
||||||
@ -1375,14 +1378,15 @@ TEST(Reader, ParseTerminationByHandler) {
|
|||||||
TEST_TERMINATION(4, "[-1234567890123456789");
|
TEST_TERMINATION(4, "[-1234567890123456789");
|
||||||
TEST_TERMINATION(5, "[1234567890123456789");
|
TEST_TERMINATION(5, "[1234567890123456789");
|
||||||
TEST_TERMINATION(6, "[0.5]");
|
TEST_TERMINATION(6, "[0.5]");
|
||||||
TEST_TERMINATION(7, "[\"a\"");
|
// RawNumber() is never called
|
||||||
TEST_TERMINATION(8, "[{");
|
TEST_TERMINATION(8, "[\"a\"");
|
||||||
TEST_TERMINATION(9, "[{\"a\"");
|
TEST_TERMINATION(9, "[{");
|
||||||
TEST_TERMINATION(10, "[{}");
|
TEST_TERMINATION(10, "[{\"a\"");
|
||||||
TEST_TERMINATION(10, "[{\"a\":1}"); // non-empty object
|
TEST_TERMINATION(11, "[{}");
|
||||||
TEST_TERMINATION(11, "{\"a\":[");
|
TEST_TERMINATION(11, "[{\"a\":1}"); // non-empty object
|
||||||
TEST_TERMINATION(12, "{\"a\":[]");
|
TEST_TERMINATION(12, "{\"a\":[");
|
||||||
TEST_TERMINATION(12, "{\"a\":[1]"); // non-empty array
|
TEST_TERMINATION(13, "{\"a\":[]");
|
||||||
|
TEST_TERMINATION(13, "{\"a\":[1]"); // non-empty array
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Reader, ParseComments) {
|
TEST(Reader, ParseComments) {
|
||||||
@ -1508,6 +1512,46 @@ TEST(Reader, UnrecognizedComment) {
|
|||||||
EXPECT_EQ(kParseErrorUnspecificSyntaxError, reader.GetParseErrorCode());
|
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__
|
#ifdef __GNUC__
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
@ -1644,12 +1644,13 @@ struct TerminateHandler {
|
|||||||
bool Int64(int64_t) { return e != 4; }
|
bool Int64(int64_t) { return e != 4; }
|
||||||
bool Uint64(uint64_t) { return e != 5; }
|
bool Uint64(uint64_t) { return e != 5; }
|
||||||
bool Double(double) { return e != 6; }
|
bool Double(double) { return e != 6; }
|
||||||
bool String(const char*, SizeType, bool) { return e != 7; }
|
bool RawNumber(const char*, SizeType, bool) { return e != 7; }
|
||||||
bool StartObject() { return e != 8; }
|
bool String(const char*, SizeType, bool) { return e != 8; }
|
||||||
bool Key(const char*, SizeType, bool) { return e != 9; }
|
bool StartObject() { return e != 9; }
|
||||||
bool EndObject(SizeType) { return e != 10; }
|
bool Key(const char*, SizeType, bool) { return e != 10; }
|
||||||
bool StartArray() { return e != 11; }
|
bool EndObject(SizeType) { return e != 11; }
|
||||||
bool EndArray(SizeType) { return e != 12; }
|
bool StartArray() { return e != 12; }
|
||||||
|
bool EndArray(SizeType) { return e != 13; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TEST_TERMINATION(e, json)\
|
#define TEST_TERMINATION(e, json)\
|
||||||
@ -1670,12 +1671,13 @@ TEST(Value, AcceptTerminationByHandler) {
|
|||||||
TEST_TERMINATION(4, "[-1234567890123456789]");
|
TEST_TERMINATION(4, "[-1234567890123456789]");
|
||||||
TEST_TERMINATION(5, "[9223372036854775808]");
|
TEST_TERMINATION(5, "[9223372036854775808]");
|
||||||
TEST_TERMINATION(6, "[0.5]");
|
TEST_TERMINATION(6, "[0.5]");
|
||||||
TEST_TERMINATION(7, "[\"a\"]");
|
// RawNumber() is never called
|
||||||
TEST_TERMINATION(8, "[{}]");
|
TEST_TERMINATION(8, "[\"a\"]");
|
||||||
TEST_TERMINATION(9, "[{\"a\":1}]");
|
TEST_TERMINATION(9, "[{}]");
|
||||||
TEST_TERMINATION(10, "[{}]");
|
TEST_TERMINATION(10, "[{\"a\":1}]");
|
||||||
TEST_TERMINATION(11, "{\"a\":[]}");
|
TEST_TERMINATION(11, "[{}]");
|
||||||
TEST_TERMINATION(12, "{\"a\":[]}");
|
TEST_TERMINATION(12, "{\"a\":[]}");
|
||||||
|
TEST_TERMINATION(13, "{\"a\":[]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ValueIntComparer {
|
struct ValueIntComparer {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user