Merge branch 'master' into issue23errorcode
Conflicts: example/condense/condense.cpp include/rapidjson/reader.h test/unittest/readertest.cpp
This commit is contained in:
commit
389fe87cd8
@ -21,6 +21,8 @@ before_script:
|
|||||||
- cd "${TRAVIS_BUILD_DIR}"
|
- cd "${TRAVIS_BUILD_DIR}"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- make -C build/gmake -f test.make unittest
|
- make -C build/gmake -f test.make
|
||||||
|
- make -C build/gmake -f example.make
|
||||||
- cd bin
|
- cd bin
|
||||||
- ./unittest_${config_suffix}
|
- ./unittest_${config_suffix}
|
||||||
|
- ./perftest_${config_suffix}
|
||||||
|
@ -149,8 +149,8 @@ solution "example"
|
|||||||
configuration "vs*"
|
configuration "vs*"
|
||||||
defines { "_CRT_SECURE_NO_WARNINGS" }
|
defines { "_CRT_SECURE_NO_WARNINGS" }
|
||||||
|
|
||||||
configuration "gmake"
|
-- configuration "gmake"
|
||||||
buildoptions "-Weverything"
|
-- buildoptions "-Weverything"
|
||||||
|
|
||||||
project "condense"
|
project "condense"
|
||||||
kind "ConsoleApp"
|
kind "ConsoleApp"
|
||||||
@ -176,3 +176,8 @@ solution "example"
|
|||||||
kind "ConsoleApp"
|
kind "ConsoleApp"
|
||||||
files "../example/serialize/*"
|
files "../example/serialize/*"
|
||||||
setTargetObjDir("../bin")
|
setTargetObjDir("../bin")
|
||||||
|
|
||||||
|
project "simpledom"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
files "../example/simpledom/*"
|
||||||
|
setTargetObjDir("../bin")
|
||||||
|
8
doc/diagram/makefile
Normal file
8
doc/diagram/makefile
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
%.pdf: %.dot
|
||||||
|
dot $< -Tpdf -o $@
|
||||||
|
|
||||||
|
%.png: %.dot
|
||||||
|
dot $< -Tpng -o $@
|
||||||
|
|
||||||
|
DOTFILES = $(basename $(wildcard *.dot))
|
||||||
|
all: $(addsuffix .png, $(DOTFILES)) #$(addsuffix .pdf, $(DOTFILES))
|
54
doc/diagram/simpledom.dot
Normal file
54
doc/diagram/simpledom.dot
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
digraph {
|
||||||
|
compound=true
|
||||||
|
fontname="Inconsolata, Consolas"
|
||||||
|
fontsize=10
|
||||||
|
margin="0,0"
|
||||||
|
ranksep=0.2
|
||||||
|
penwidth=0.5
|
||||||
|
|
||||||
|
node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5]
|
||||||
|
edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal]
|
||||||
|
|
||||||
|
{
|
||||||
|
node [shape=record, fontsize="8", margin="0.04", height=0.2, color=gray]
|
||||||
|
srcjson [label="\{|p|r|o|j|e|c|t|\"|:|\"|r|a|p|i|d|j|s|o|n|\"|,|\"|s|t|a|r|s|\"|:|1|0|\}"]
|
||||||
|
dstjson [label="\{|p|r|o|j|e|c|t|\"|:|\"|r|a|p|i|d|j|s|o|n|\"|,|\"|s|t|a|r|s|\"|:|1|1|\}"]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
node [shape="box", style="filled", fillcolor="gray95"]
|
||||||
|
Document2 [label="(Modified) Document"]
|
||||||
|
Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
subgraph cluster1 {
|
||||||
|
margin="10,10"
|
||||||
|
labeljust="left"
|
||||||
|
label = "Document"
|
||||||
|
style=filled
|
||||||
|
fillcolor=gray95
|
||||||
|
node [shape=Mrecord, style=filled, colorscheme=spectral7]
|
||||||
|
|
||||||
|
root [label="{object|}", fillcolor=3]
|
||||||
|
|
||||||
|
{
|
||||||
|
project [label="{string|\"project\"}", fillcolor=5]
|
||||||
|
rapidjson [label="{string|\"rapidjson\"}", fillcolor=5]
|
||||||
|
stars [label="{string|\"stars\"}", fillcolor=5]
|
||||||
|
ten [label="{number|10}", fillcolor=6]
|
||||||
|
}
|
||||||
|
|
||||||
|
edge [arrowhead=vee]
|
||||||
|
root -> { project, stars }
|
||||||
|
|
||||||
|
edge [arrowhead="none"]
|
||||||
|
project -> rapidjson
|
||||||
|
stars -> ten
|
||||||
|
}
|
||||||
|
|
||||||
|
srcjson -> root [label=" Parse()", lhead="cluster1"]
|
||||||
|
|
||||||
|
ten -> Document2 [label=" Increase \"stars\"", ltail="cluster1" ]
|
||||||
|
Document2 -> Writer [label=" Traverse DOM by Accept()"]
|
||||||
|
Writer -> dstjson [label=" Output to StringBuffer"]
|
||||||
|
}
|
BIN
doc/diagram/simpledom.png
Normal file
BIN
doc/diagram/simpledom.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
79
doc/features.md
Normal file
79
doc/features.md
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# RapidJSON Features
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
* Cross-platform
|
||||||
|
* Compilers: Visual Studio, gcc, clang, etc.
|
||||||
|
* Architectures: x86, x64, ARM, etc.
|
||||||
|
* Operating systems: Windows, Mac OS X, Linux, iOS, Android, etc.
|
||||||
|
* Easy installation
|
||||||
|
* Header files only library. Just copy the headers to your project.
|
||||||
|
* Self-contained, minimal dependences
|
||||||
|
* No STL, BOOST, etc.
|
||||||
|
* Only included `<cstdio>`, `<cstdlib>`, `<cstring>`, `<inttypes.h>`, `<new>`, `<stdint.h>`. *
|
||||||
|
* Without C++ exception, RTTI
|
||||||
|
* High performance
|
||||||
|
* Use template and inline functions to reduce function call overheads.
|
||||||
|
* Optional SSE2/SSE4.1 support.
|
||||||
|
|
||||||
|
## Standard compliance
|
||||||
|
|
||||||
|
* RapidJSON should be fully RFC4627/ECMA-404 compliance.
|
||||||
|
* Support unicode surrogate.
|
||||||
|
* Support null character (`"\u0000"`)
|
||||||
|
* For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string.
|
||||||
|
|
||||||
|
## Unicode
|
||||||
|
|
||||||
|
* Support UTF-8, UTF-16, UTF-32 encodings, including little endian and big endian.
|
||||||
|
* These encodings are used in input/output streams and in-memory representation.
|
||||||
|
* Support automatic detection of encodings in input stream.
|
||||||
|
* Support transcoding between encodings internally.
|
||||||
|
* For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM.
|
||||||
|
* Support encoding validation internally.
|
||||||
|
* For example, you can read a UTF-8 file, and let RapidJSON check whether all JSON strings are valid UTF-8 byte sequence.
|
||||||
|
* Support custom character types.
|
||||||
|
* By default the character types are `char` for UTF8, `wchar_t` for UTF16, `uint32_t` for UTF32.
|
||||||
|
* Support custom encodings.
|
||||||
|
|
||||||
|
## API styles
|
||||||
|
|
||||||
|
* SAX (Simple API for XML) style API
|
||||||
|
* Similar to [SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSON provides a event sequential access parser API (`GenericReader`). It also provides a generator API (`GenericWriter`) which consumes the same set of events.
|
||||||
|
* DOM (Document Object Model) style API
|
||||||
|
* Similar to [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) for HTML/XML, RapidJSON can parse JSON into a DOM representation (`GenericDocument`), for easy manipulation, and finally stringify back to JSON if needed.
|
||||||
|
* The DOM style API (`GenericDocument`) is actually implemented with SAX style API (`GenericReader`). SAX is faster but sometimes DOM is easier. Users can pick their choices according to scenarios.
|
||||||
|
|
||||||
|
## DOM (Document)
|
||||||
|
|
||||||
|
* Support insitu parsing.
|
||||||
|
* Parse JSON string values in-place at the source JSON, and then the DOM points to addresses of those strings.
|
||||||
|
* Faster than convention parsing: no allocation for strings, no copy (if string does not contain escapes), cache-friendly.
|
||||||
|
* Support 32-bit/64-bit signed/unsigned integer and `double` for JSON number type.
|
||||||
|
* RapidJSON checks range of numerical values for conversions.
|
||||||
|
|
||||||
|
## SAX (Reader)
|
||||||
|
|
||||||
|
* Support comprehensive error code if parsing failed.
|
||||||
|
* Support localizable error message.
|
||||||
|
|
||||||
|
## SAX (Writer)
|
||||||
|
|
||||||
|
* Support PrettyWriter for adding newlines and indentations.
|
||||||
|
* Support custom precision for floating point values.
|
||||||
|
|
||||||
|
## Stream
|
||||||
|
|
||||||
|
* Support `GenericStringBuffer` for storing the output JSON as string.
|
||||||
|
* Support `FileReadStream`/`FileWriteStream` for input/output `FILE` object.
|
||||||
|
* Support custom streams.
|
||||||
|
|
||||||
|
## Memory
|
||||||
|
|
||||||
|
* Minimize memory overheads for DOM.
|
||||||
|
* Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string).
|
||||||
|
* Support fast default allocator.
|
||||||
|
* A stack-based allocator (allocate sequentially, prohibit to free individual allocations, suitable for parsing).
|
||||||
|
* User can provide a pre-allocated buffer. (Possible to parse a number of JSONs without any CRT allocation)
|
||||||
|
* Support standard CRT(C-runtime) allocator.
|
||||||
|
* Support custom allocators.
|
@ -23,7 +23,7 @@ int main(int, char*[]) {
|
|||||||
Writer<FileWriteStream> writer(os);
|
Writer<FileWriteStream> writer(os);
|
||||||
|
|
||||||
// JSON reader parse from the input stream and let writer generate the output.
|
// JSON reader parse from the input stream and let writer generate the output.
|
||||||
if (!reader.Parse<0>(is, writer)) {
|
if (!reader.Parse(is, writer)) {
|
||||||
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), GetParseError_En(reader.GetParseErrorCode()));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
29
example/simpledom/simpledom.cpp
Normal file
29
example/simpledom/simpledom.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// JSON simple example
|
||||||
|
// This example does not handle errors.
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "rapidjson/writer.h"
|
||||||
|
#include "rapidjson/stringbuffer.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// 1. Parse a JSON string into DOM.
|
||||||
|
const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
|
||||||
|
Document d;
|
||||||
|
d.Parse(json);
|
||||||
|
|
||||||
|
// 2. Modify it by DOM.
|
||||||
|
Value& s = d["stars"];
|
||||||
|
s.SetInt(s.GetInt() + 1);
|
||||||
|
|
||||||
|
// 3. Stringify the DOM
|
||||||
|
StringBuffer buffer;
|
||||||
|
Writer<StringBuffer> writer(buffer);
|
||||||
|
d.Accept(writer);
|
||||||
|
|
||||||
|
// Output {"project":"rapidjson","stars":11}
|
||||||
|
std::cout << buffer.GetString() << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
@ -19,14 +19,14 @@ int main(int, char*[]) {
|
|||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream().
|
// "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream().
|
||||||
if (document.Parse<0>(json).HasParseError())
|
if (document.Parse(json).HasParseError())
|
||||||
return 1;
|
return 1;
|
||||||
#else
|
#else
|
||||||
// In-situ parsing, decode strings directly in the source string. Source must be string.
|
// In-situ parsing, decode strings directly in the source string. Source must be string.
|
||||||
{
|
{
|
||||||
char buffer[sizeof(json)];
|
char buffer[sizeof(json)];
|
||||||
memcpy(buffer, json, sizeof(json));
|
memcpy(buffer, json, sizeof(json));
|
||||||
if (document.ParseInsitu<0>(buffer).HasParseError())
|
if (document.ParseInsitu(buffer).HasParseError())
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -202,7 +202,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename SourceAllocator>
|
template <typename SourceAllocator>
|
||||||
GenericValue& CopyFrom(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator) {
|
GenericValue& CopyFrom(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator) {
|
||||||
RAPIDJSON_ASSERT((void*)this != (void*)&rhs);
|
RAPIDJSON_ASSERT((void*)this != (void const*)&rhs);
|
||||||
this->~GenericValue();
|
this->~GenericValue();
|
||||||
new (this) GenericValue(rhs,allocator);
|
new (this) GenericValue(rhs,allocator);
|
||||||
return *this;
|
return *this;
|
||||||
@ -818,6 +818,11 @@ public:
|
|||||||
return ParseStream<parseFlags,Encoding,InputStream>(is);
|
return ParseStream<parseFlags,Encoding,InputStream>(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
GenericDocument& ParseStream(InputStream& is) {
|
||||||
|
return ParseStream<0, Encoding, InputStream>(is);
|
||||||
|
}
|
||||||
|
|
||||||
//! Parse JSON text from a mutable string.
|
//! Parse JSON text from a mutable string.
|
||||||
/*! \tparam parseFlags Combination of ParseFlag.
|
/*! \tparam parseFlags Combination of ParseFlag.
|
||||||
\param str Mutable zero-terminated string to be parsed.
|
\param str Mutable zero-terminated string to be parsed.
|
||||||
@ -834,6 +839,10 @@ public:
|
|||||||
return ParseInsitu<parseFlags, Encoding>(str);
|
return ParseInsitu<parseFlags, Encoding>(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GenericDocument& ParseInsitu(Ch* str) {
|
||||||
|
return ParseInsitu<0, Encoding>(str);
|
||||||
|
}
|
||||||
|
|
||||||
//! Parse JSON text from a read-only string.
|
//! Parse JSON text from a read-only string.
|
||||||
/*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).
|
/*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag).
|
||||||
\param str Read-only zero-terminated string to be parsed.
|
\param str Read-only zero-terminated string to be parsed.
|
||||||
@ -850,6 +859,10 @@ public:
|
|||||||
return Parse<parseFlags, Encoding>(str);
|
return Parse<parseFlags, Encoding>(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GenericDocument& Parse(const Ch* str) {
|
||||||
|
return Parse<0>(str);
|
||||||
|
}
|
||||||
|
|
||||||
//! Whether a parse error was occured in the last parsing.
|
//! Whether a parse error was occured in the last parsing.
|
||||||
bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; }
|
bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; }
|
||||||
|
|
||||||
|
@ -69,6 +69,11 @@ private:
|
|||||||
bool eof_;
|
bool eof_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct StreamTraits<FileReadStream> {
|
||||||
|
typedef FileReadStream StreamCopyType; // Enable stream copy optimization.
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace rapidjson
|
} // namespace rapidjson
|
||||||
|
|
||||||
#endif // RAPIDJSON_FILESTREAM_H_
|
#endif // RAPIDJSON_FILESTREAM_H_
|
||||||
|
@ -193,6 +193,24 @@ concept Stream {
|
|||||||
\endcode
|
\endcode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//! Provides additional information for stream.
|
||||||
|
/*!
|
||||||
|
By using traits pattern, this type provides a default configuration for stream.
|
||||||
|
For custom stream, this type can be specialized for other configuration.
|
||||||
|
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
|
||||||
|
*/
|
||||||
|
template<typename Stream>
|
||||||
|
struct StreamTraits {
|
||||||
|
//! Whether to make local copy of stream for optimization during parsing.
|
||||||
|
/*!
|
||||||
|
If it is defined as Stream&, it will not make a local copy.
|
||||||
|
If it is defined as Stream, it will make a local copy for optimization.
|
||||||
|
By default, for safety, streams do not use local copy optimization, i.e. it is defined as Stream&.
|
||||||
|
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
|
||||||
|
*/
|
||||||
|
typedef Stream& StreamCopyType;
|
||||||
|
};
|
||||||
|
|
||||||
//! Put N copies of a character to a stream.
|
//! Put N copies of a character to a stream.
|
||||||
template<typename Stream, typename Ch>
|
template<typename Stream, typename Ch>
|
||||||
inline void PutN(Stream& stream, Ch c, size_t n) {
|
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||||
@ -225,6 +243,11 @@ struct GenericStringStream {
|
|||||||
const Ch* head_; //!< Original head of the string.
|
const Ch* head_; //!< Original head of the string.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<GenericStringStream<Encoding> > {
|
||||||
|
typedef GenericStringStream<Encoding> StreamCopyType; // Enable stream copy optimization.
|
||||||
|
};
|
||||||
|
|
||||||
typedef GenericStringStream<UTF8<> > StringStream;
|
typedef GenericStringStream<UTF8<> > StringStream;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -256,6 +279,11 @@ struct GenericInsituStringStream {
|
|||||||
Ch* head_;
|
Ch* head_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<GenericInsituStringStream<Encoding> > {
|
||||||
|
typedef GenericInsituStringStream<Encoding> StreamCopyType; // Enable stream copy optimization.
|
||||||
|
};
|
||||||
|
|
||||||
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -135,7 +135,7 @@ struct BaseReaderHandler {
|
|||||||
*/
|
*/
|
||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
void SkipWhitespace(InputStream& is) {
|
void SkipWhitespace(InputStream& is) {
|
||||||
InputStream s = is; // Use a local copy for optimization
|
typename StreamTraits<InputStream>::StreamCopyType s = is; // Use a local copy for optimization
|
||||||
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
|
||||||
s.Take();
|
s.Take();
|
||||||
is = s;
|
is = s;
|
||||||
@ -283,8 +283,15 @@ public:
|
|||||||
return !HasParseError();
|
return !HasParseError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename Handler>
|
||||||
|
bool Parse(InputStream& is, Handler& handler) {
|
||||||
|
return Parse<0>(is, handler);
|
||||||
|
}
|
||||||
|
|
||||||
bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; }
|
bool HasParseError() const { return parseErrorCode_ != kParseErrorNone; }
|
||||||
|
|
||||||
ParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
|
ParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
|
||||||
|
|
||||||
size_t GetErrorOffset() const { return errorOffset_; }
|
size_t GetErrorOffset() const { return errorOffset_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -399,7 +406,7 @@ private:
|
|||||||
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
// Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
|
||||||
template<typename InputStream>
|
template<typename InputStream>
|
||||||
unsigned ParseHex4(InputStream& is) {
|
unsigned ParseHex4(InputStream& is) {
|
||||||
InputStream s = is; // Use a local copy for optimization
|
typename StreamTraits<InputStream>::StreamCopyType s = is; // Use a local copy for optimization
|
||||||
unsigned codepoint = 0;
|
unsigned codepoint = 0;
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
Ch c = s.Take();
|
Ch c = s.Take();
|
||||||
@ -440,7 +447,7 @@ private:
|
|||||||
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
// Parse string and generate String event. Different code paths for kParseInsituFlag.
|
||||||
template<unsigned parseFlags, typename InputStream, typename Handler>
|
template<unsigned parseFlags, typename InputStream, typename Handler>
|
||||||
void ParseString(InputStream& is, Handler& handler) {
|
void ParseString(InputStream& is, Handler& handler) {
|
||||||
InputStream s = is; // Local copy for optimization
|
typename StreamTraits<InputStream>::StreamCopyType s = is; // Local copy for optimization
|
||||||
if (parseFlags & kParseInsituFlag) {
|
if (parseFlags & kParseInsituFlag) {
|
||||||
Ch *head = s.PutBegin();
|
Ch *head = s.PutBegin();
|
||||||
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
|
||||||
@ -520,7 +527,7 @@ 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) {
|
||||||
InputStream s = is; // Local copy for optimization
|
typename StreamTraits<InputStream>::StreamCopyType s = is; // Local copy for optimization
|
||||||
// Parse minus
|
// Parse minus
|
||||||
bool minus = false;
|
bool minus = false;
|
||||||
if (s.Peek() == '-') {
|
if (s.Peek() == '-') {
|
||||||
|
48
readme.md
48
readme.md
@ -16,7 +16,9 @@ Rapidjson is a JSON parser and generator for C++. It was inspired by [rapidxml](
|
|||||||
|
|
||||||
* Rapidjson is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
|
* Rapidjson is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing.
|
||||||
|
|
||||||
For the full features please refer to the user guide.
|
* Rapidjson is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validataton and transcoding internally. For example, you can read a UTF-8 file and let rapidjson transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character).
|
||||||
|
|
||||||
|
More features can be read [here](doc/features.md).
|
||||||
|
|
||||||
JSON(JavaScript Object Notation) is a light-weight data exchange format. Rapidjson should be in fully compliance with RFC4627/ECMA-404. More information about JSON can be obtained at
|
JSON(JavaScript Object Notation) is a light-weight data exchange format. Rapidjson should be in fully compliance with RFC4627/ECMA-404. More information about JSON can be obtained at
|
||||||
* [Introducing JSON](http://json.org/)
|
* [Introducing JSON](http://json.org/)
|
||||||
@ -39,9 +41,51 @@ Rapidjson is a header-only C++ library. Just copy the `rapidjson/include/rapidjs
|
|||||||
|
|
||||||
To build the tests and examples:
|
To build the tests and examples:
|
||||||
|
|
||||||
1. Obtain [premake4] (http://industriousone.com/premake/download).
|
1. Obtain [premake4](http://industriousone.com/premake/download).
|
||||||
2. Copy premake4 executable to rapidjson/build (or system path)
|
2. Copy premake4 executable to rapidjson/build (or system path)
|
||||||
3. Run `rapidjson/build/premake.bat` on Windows, `rapidjson/build/premake.sh` on Linux or other platforms
|
3. Run `rapidjson/build/premake.bat` on Windows, `rapidjson/build/premake.sh` on Linux or other platforms
|
||||||
4. On Windows, build the solution at `rapidjson/build/vs2008/` or `/vs2010/`
|
4. On Windows, build the solution at `rapidjson/build/vs2008/` or `/vs2010/`
|
||||||
5. On other platforms, run GNU make at `rapidjson/build/gmake/` (e.g., `make -f test.make config=release32`, `make -f example.make config=debug32`)
|
5. On other platforms, run GNU make at `rapidjson/build/gmake/` (e.g., `make -f test.make config=release32`, `make -f example.make config=debug32`)
|
||||||
6. On success, the executable are generated at `rapidjson/bin`
|
6. On success, the executable are generated at `rapidjson/bin`
|
||||||
|
|
||||||
|
## Usage at a glance
|
||||||
|
|
||||||
|
This simple example parses a JSON string into a document (DOM), make a simple modification of the DOM, and finally stringify the DOM to a JSON string.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// example/simpledom/simpledom.cpp
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "rapidjson/writer.h"
|
||||||
|
#include "rapidjson/stringbuffer.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// 1. Parse a JSON string into DOM.
|
||||||
|
const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
|
||||||
|
Document d;
|
||||||
|
d.Parse(json);
|
||||||
|
|
||||||
|
// 2. Modify it by DOM.
|
||||||
|
Value& s = d["stars"];
|
||||||
|
s.SetInt(s.GetInt() + 1);
|
||||||
|
|
||||||
|
// 3. Stringify the DOM
|
||||||
|
StringBuffer buffer;
|
||||||
|
Writer<StringBuffer> writer(buffer);
|
||||||
|
d.Accept(writer);
|
||||||
|
|
||||||
|
// Output {"project":"rapidjson","stars":11}
|
||||||
|
std::cout << buffer.GetString() << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that this exmample did not handle potential errors.
|
||||||
|
|
||||||
|
The following diagram shows the process.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
More [examples](example/) are avaliable.
|
||||||
|
@ -28,7 +28,7 @@ public:
|
|||||||
temp_ = (char *)malloc(length_ + 1);
|
temp_ = (char *)malloc(length_ + 1);
|
||||||
|
|
||||||
// Parse as a document
|
// Parse as a document
|
||||||
EXPECT_FALSE(doc_.Parse<0>(json_).IsNull());
|
EXPECT_FALSE(doc_.Parse(json_).IsNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void TearDown() {
|
virtual void TearDown() {
|
||||||
@ -66,7 +66,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) {
|
|||||||
StringStream s(json_);
|
StringStream s(json_);
|
||||||
BaseReaderHandler<> h;
|
BaseReaderHandler<> h;
|
||||||
Reader reader;
|
Reader reader;
|
||||||
EXPECT_TRUE(reader.Parse<0>(s, h));
|
EXPECT_TRUE(reader.Parse(s, h));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParseInsitu_MemoryPoolAllocator)) {
|
|||||||
//MemoryPoolAllocator<> allocator(userBuffer, userBufferSize);
|
//MemoryPoolAllocator<> allocator(userBuffer, userBufferSize);
|
||||||
//Document doc(&allocator);
|
//Document doc(&allocator);
|
||||||
Document doc;
|
Document doc;
|
||||||
doc.ParseInsitu<0>(temp_);
|
doc.ParseInsitu(temp_);
|
||||||
ASSERT_TRUE(doc.IsObject());
|
ASSERT_TRUE(doc.IsObject());
|
||||||
//if (i == 0) {
|
//if (i == 0) {
|
||||||
// size_t size = doc.GetAllocator().Size();
|
// size_t size = doc.GetAllocator().Size();
|
||||||
@ -110,7 +110,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParse_MemoryPoolAllocator)) {
|
|||||||
//MemoryPoolAllocator<> allocator(userBuffer, userBufferSize);
|
//MemoryPoolAllocator<> allocator(userBuffer, userBufferSize);
|
||||||
//Document doc(&allocator);
|
//Document doc(&allocator);
|
||||||
Document doc;
|
Document doc;
|
||||||
doc.Parse<0>(json_);
|
doc.Parse(json_);
|
||||||
ASSERT_TRUE(doc.IsObject());
|
ASSERT_TRUE(doc.IsObject());
|
||||||
//if (i == 0) {
|
//if (i == 0) {
|
||||||
// size_t size = doc.GetAllocator().Size();
|
// size_t size = doc.GetAllocator().Size();
|
||||||
@ -128,7 +128,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParse_CrtAllocator)) {
|
|||||||
for (size_t i = 0; i < kTrialCount; i++) {
|
for (size_t i = 0; i < kTrialCount; i++) {
|
||||||
memcpy(temp_, json_, length_ + 1);
|
memcpy(temp_, json_, length_ + 1);
|
||||||
GenericDocument<UTF8<>, CrtAllocator> doc;
|
GenericDocument<UTF8<>, CrtAllocator> doc;
|
||||||
doc.Parse<0>(temp_);
|
doc.Parse(temp_);
|
||||||
ASSERT_TRUE(doc.IsObject());
|
ASSERT_TRUE(doc.IsObject());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ TEST_F(RapidJson, internal_Pow10) {
|
|||||||
TEST_F(RapidJson, SIMD_SUFFIX(Whitespace)) {
|
TEST_F(RapidJson, SIMD_SUFFIX(Whitespace)) {
|
||||||
for (size_t i = 0; i < kTrialCount; i++) {
|
for (size_t i = 0; i < kTrialCount; i++) {
|
||||||
Document doc;
|
Document doc;
|
||||||
ASSERT_TRUE(doc.Parse<0>(whitespace_).IsArray());
|
ASSERT_TRUE(doc.Parse(whitespace_).IsArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) {
|
|||||||
FileReadStream s(fp, buffer, sizeof(buffer));
|
FileReadStream s(fp, buffer, sizeof(buffer));
|
||||||
BaseReaderHandler<> h;
|
BaseReaderHandler<> h;
|
||||||
Reader reader;
|
Reader reader;
|
||||||
reader.Parse<0>(s, h);
|
reader.Parse(s, h);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ using namespace rapidjson;
|
|||||||
TEST(Document, Parse) {
|
TEST(Document, Parse) {
|
||||||
Document doc;
|
Document doc;
|
||||||
|
|
||||||
doc.Parse<0>(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||||
|
|
||||||
EXPECT_TRUE(doc.IsObject());
|
EXPECT_TRUE(doc.IsObject());
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ struct OutputStringStream : public std::ostringstream {
|
|||||||
|
|
||||||
TEST(Document, AcceptWriter) {
|
TEST(Document, AcceptWriter) {
|
||||||
Document doc;
|
Document doc;
|
||||||
doc.Parse<0>(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ");
|
||||||
|
|
||||||
OutputStringStream os;
|
OutputStringStream os;
|
||||||
Writer<OutputStringStream> writer(os);
|
Writer<OutputStringStream> writer(os);
|
||||||
|
@ -42,7 +42,7 @@ TEST(JsonChecker, Reader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||||
if (!document.Parse<0>((const char*)json).HasParseError())
|
if (!document.Parse((const char*)json).HasParseError())
|
||||||
FAIL();
|
FAIL();
|
||||||
//printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError());
|
//printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError());
|
||||||
free(json);
|
free(json);
|
||||||
@ -63,7 +63,7 @@ TEST(JsonChecker, Reader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
GenericDocument<UTF8<>, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak)
|
||||||
document.Parse<0>((const char*)json);
|
document.Parse((const char*)json);
|
||||||
EXPECT_TRUE(!document.HasParseError());
|
EXPECT_TRUE(!document.HasParseError());
|
||||||
free(json);
|
free(json);
|
||||||
}
|
}
|
||||||
|
@ -603,3 +603,51 @@ TEST(Reader, SkipWhitespace) {
|
|||||||
EXPECT_EQ(expected[i], ss.Take());
|
EXPECT_EQ(expected[i], ss.Take());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test implementing a stream without copy stream optimization.
|
||||||
|
// Clone from GenericStringStream except that copy constructor is disabled.
|
||||||
|
template <typename Encoding>
|
||||||
|
class CustomStringStream {
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
CustomStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||||
|
|
||||||
|
Ch Peek() const { return *src_; }
|
||||||
|
Ch Take() { return *src_++; }
|
||||||
|
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Not support copy constructor.
|
||||||
|
CustomStringStream(const CustomStringStream&);
|
||||||
|
|
||||||
|
const Ch* src_; //!< Current read position.
|
||||||
|
const Ch* head_; //!< Original head of the string.
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the following code is compiled, it should generate compilation error as predicted.
|
||||||
|
// Because CustomStringStream<> is not copyable via making copy constructor private.
|
||||||
|
#if 0
|
||||||
|
namespace rapidjson {
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<CustomStringStream<Encoding> > {
|
||||||
|
typedef CustomStringStream<Encoding> StreamCopyType;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rapdijson
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST(Reader, CustomStringStream) {
|
||||||
|
const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } ";
|
||||||
|
CustomStringStream<UTF8<char> > s(json);
|
||||||
|
ParseObjectHandler h;
|
||||||
|
Reader reader;
|
||||||
|
reader.ParseObject<0>(s, h);
|
||||||
|
EXPECT_EQ(20u, h.step_);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user