1 // Example of parsing JSON to document by parts.
4 // Temporarily disable for clang (older version) due to incompatibility with libstdc++
5 #if (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700)) && !defined(__clang__)
7 #include "rapidjson/document.h"
8 #include "rapidjson/error/en.h"
9 #include "rapidjson/writer.h"
10 #include "rapidjson/ostreamwrapper.h"
11 #include <condition_variable>
16 using namespace rapidjson;
18 template<unsigned parseFlags = kParseDefaultFlags>
19 class AsyncDocumentParser {
21 AsyncDocumentParser(Document& d)
24 , parseThread_(&AsyncDocumentParser::Parse, this)
31 ~AsyncDocumentParser() {
32 if (!parseThread_.joinable())
36 std::unique_lock<std::mutex> lock(mutex_);
38 // Wait until the buffer is read up (or parsing is completed)
39 while (!stream_.Empty() && !completed_)
42 // Automatically append '\0' as the terminator in the stream.
43 static const char terminator[] = "";
44 stream_.src_ = terminator;
45 stream_.end_ = terminator + 1;
46 notEmpty_.notify_one(); // unblock the AsyncStringStream
52 void ParsePart(const char* buffer, size_t length) {
53 std::unique_lock<std::mutex> lock(mutex_);
55 // Wait until the buffer is read up (or parsing is completed)
56 while (!stream_.Empty() && !completed_)
59 // Stop further parsing if the parsing process is completed.
63 // Set the buffer to stream and unblock the AsyncStringStream
64 stream_.src_ = buffer;
65 stream_.end_ = buffer + length;
66 notEmpty_.notify_one();
71 d_.ParseStream<parseFlags>(stream_);
73 // The stream may not be fully read, notify finish anyway to unblock ParsePart()
74 std::unique_lock<std::mutex> lock(mutex_);
75 completed_ = true; // Parsing process is completed
76 finish_.notify_one(); // Unblock ParsePart() or destructor if they are waiting.
79 struct AsyncStringStream {
82 AsyncStringStream(AsyncDocumentParser& parser) : parser_(parser), src_(), end_(), count_() {}
85 std::unique_lock<std::mutex> lock(parser_.mutex_);
87 // If nothing in stream, block to wait.
89 parser_.notEmpty_.wait(lock);
95 std::unique_lock<std::mutex> lock(parser_.mutex_);
97 // If nothing in stream, block to wait.
99 parser_.notEmpty_.wait(lock);
104 // If all stream is read up, notify that the stream is finish.
106 parser_.finish_.notify_one();
111 size_t Tell() const { return count_; }
114 char* PutBegin() { return 0; }
117 size_t PutEnd(char*) { return 0; }
119 bool Empty() const { return src_ == end_; }
121 AsyncDocumentParser& parser_;
122 const char* src_; //!< Current read position.
123 const char* end_; //!< End of buffer
124 size_t count_; //!< Number of characters taken so far.
127 AsyncStringStream stream_;
129 std::thread parseThread_;
131 std::condition_variable notEmpty_;
132 std::condition_variable finish_;
140 AsyncDocumentParser<> parser(d);
142 const char json1[] = " { \"hello\" : \"world\", \"t\" : tr";
143 //const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // Fot test parsing error
144 const char json2[] = "ue, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.14";
145 const char json3[] = "16, \"a\":[1, 2, 3, 4] } ";
147 parser.ParsePart(json1, sizeof(json1) - 1);
148 parser.ParsePart(json2, sizeof(json2) - 1);
149 parser.ParsePart(json3, sizeof(json3) - 1);
152 if (d.HasParseError()) {
153 std::cout << "Error at offset " << d.GetErrorOffset() << ": " << GetParseError_En(d.GetParseError()) << std::endl;
157 // Stringify the JSON to cout
158 OStreamWrapper os(std::cout);
159 Writer<OStreamWrapper> writer(os);
161 std::cout << std::endl;
166 #else // Not supporting C++11
170 std::cout << "This example requires C++11 compiler" << std::endl;