Commit 2d5d9363 authored by Milo Yip's avatar Milo Yip

Merge pull request #556 from miloyip/example_parsebyparts

Add parse-by-parts example
parents 4de9ba54 c62a19cf
...@@ -48,32 +48,68 @@ matrix: ...@@ -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: ...@@ -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
......
# 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 ...@@ -8,6 +5,7 @@ set(EXAMPLES
condense condense
jsonx jsonx
messagereader messagereader
parsebyparts
pretty pretty
prettyauto prettyauto
schemavalidator schemavalidator
...@@ -24,7 +22,7 @@ add_definitions(-D__STDC_FORMAT_MACROS) ...@@ -24,7 +22,7 @@ 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} -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()
......
// 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), 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment