Commit 698496e3 authored by Milo Yip's avatar Milo Yip

Minor document adjustments

parent 4cadecd3
...@@ -10,7 +10,7 @@ Memory streams store JSON in memory. ...@@ -10,7 +10,7 @@ Memory streams store JSON in memory.
`StringStream` is the most basic input stream. It represents a complete, read-only JSON stored in memory. It is defined in `rapidjson/rapidjson.h`. `StringStream` is the most basic input stream. It represents a complete, read-only JSON stored in memory. It is defined in `rapidjson/rapidjson.h`.
```cpp ~~~~~~~~~~cpp
#include "rapidjson/document.h" // will include "rapidjson/rapidjson.h" #include "rapidjson/document.h" // will include "rapidjson/rapidjson.h"
using namespace rapidjson; using namespace rapidjson;
...@@ -21,16 +21,16 @@ StringStream s(json); ...@@ -21,16 +21,16 @@ StringStream s(json);
Document d; Document d;
d.ParseStream(s); d.ParseStream(s);
``` ~~~~~~~~~~
Since this is very common usage, `Document::Parse(const char*)` is provided to do exactly the same as above: Since this is very common usage, `Document::Parse(const char*)` is provided to do exactly the same as above:
```cpp ~~~~~~~~~~cpp
// ... // ...
const char json[] = "[1, 2, 3, 4]"; const char json[] = "[1, 2, 3, 4]";
Document d; Document d;
d.Parse(json); d.Parse(json);
``` ~~~~~~~~~~
Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user may use another encodings to represent the character set of the stream. Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user may use another encodings to represent the character set of the stream.
...@@ -38,7 +38,7 @@ Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user m ...@@ -38,7 +38,7 @@ Note that, `StringStream` is a typedef of `GenericStringStream<UTF8<> >`, user m
`StringBuffer` is a simple output stream. It allocates a memory buffer for writing the whole JSON. Use `GetString()` to obtain the buffer. `StringBuffer` is a simple output stream. It allocates a memory buffer for writing the whole JSON. Use `GetString()` to obtain the buffer.
```cpp ~~~~~~~~~~cpp
#include "rapidjson/stringbuffer.h" #include "rapidjson/stringbuffer.h"
StringBuffer buffer; StringBuffer buffer;
...@@ -46,14 +46,14 @@ Writer<StringBuffer> writer(buffer); ...@@ -46,14 +46,14 @@ Writer<StringBuffer> writer(buffer);
d.Accept(writer); d.Accept(writer);
const char* output = buffer.GetString(); const char* output = buffer.GetString();
``` ~~~~~~~~~~
When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and a initial capacity. When the buffer is full, it will increases the capacity automatically. The default capacity is 256 characters (256 bytes for UTF8, 512 bytes for UTF16, etc.). User can provide an allocator and a initial capacity.
```cpp ~~~~~~~~~~cpp
StringBuffer buffer1(0, 1024); // Use its allocator, initial size = 1024 StringBuffer buffer1(0, 1024); // Use its allocator, initial size = 1024
StringBuffer buffer2(allocator, 1024); StringBuffer buffer2(allocator, 1024);
``` ~~~~~~~~~~
By default, `StringBuffer` will instantiate an internal allocator. By default, `StringBuffer` will instantiate an internal allocator.
...@@ -69,7 +69,7 @@ However, if the JSON is big, or memory is limited, you can use `FileReadStream`. ...@@ -69,7 +69,7 @@ However, if the JSON is big, or memory is limited, you can use `FileReadStream`.
`FileReadStream` reads the file via a `FILE` pointer. And user need to provide a buffer. `FileReadStream` reads the file via a `FILE` pointer. And user need to provide a buffer.
```cpp ~~~~~~~~~~cpp
#include "rapidjson/filereadstream.h" #include "rapidjson/filereadstream.h"
#include <cstdio> #include <cstdio>
...@@ -82,7 +82,7 @@ Document d; ...@@ -82,7 +82,7 @@ Document d;
d.ParseStream(is); d.ParseStream(is);
fclose(fp); fclose(fp);
``` ~~~~~~~~~~
Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. It will be discussed very soon. Different from string streams, `FileReadStream` is byte stream. It does not handle encodings. If the file is not UTF-8, the byte stream can be wrapped in a `EncodedInputStream`. It will be discussed very soon.
...@@ -92,7 +92,7 @@ Apart from reading file, user can also use `FileReadStream` to read `stdin`. ...@@ -92,7 +92,7 @@ Apart from reading file, user can also use `FileReadStream` to read `stdin`.
`FileWriteStream` is buffered output stream. Its usage is very similar to `FileReadStream`. `FileWriteStream` is buffered output stream. Its usage is very similar to `FileReadStream`.
```cpp ~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h" #include "rapidjson/filewritestream.h"
#include <cstdio> #include <cstdio>
...@@ -109,7 +109,7 @@ Writer<FileWriteStream> writer(os); ...@@ -109,7 +109,7 @@ Writer<FileWriteStream> writer(os);
d.Accept(writer); d.Accept(writer);
fclose(fp); fclose(fp);
``` ~~~~~~~~~~
It can also directs the output to `stdout`. It can also directs the output to `stdout`.
...@@ -129,7 +129,7 @@ Note that, these encoded streams can be applied to streams other than file. For ...@@ -129,7 +129,7 @@ Note that, these encoded streams can be applied to streams other than file. For
`EncodedInputStream` has two template parameters. The first one is a `Encoding` class, such as `UTF8`, `UTF16LE`, defined in `rapidjson/encodings.h`. The second one is the class of stream to be wrapped. `EncodedInputStream` has two template parameters. The first one is a `Encoding` class, such as `UTF8`, `UTF16LE`, defined in `rapidjson/encodings.h`. The second one is the class of stream to be wrapped.
```cpp ~~~~~~~~~~cpp
#include "rapidjson/document.h" #include "rapidjson/document.h"
#include "rapidjson/filereadstream.h" // FileReadStream #include "rapidjson/filereadstream.h" // FileReadStream
#include "rapidjson/encodedstream.h" // EncodedInputStream #include "rapidjson/encodedstream.h" // EncodedInputStream
...@@ -148,13 +148,13 @@ Document d; // Document is GenericDocument<UTF8<> > ...@@ -148,13 +148,13 @@ Document d; // Document is GenericDocument<UTF8<> >
d.ParseStream<0, UTF16LE<> >(eis); // Parses UTF-16LE file into UTF-8 in memory d.ParseStream<0, UTF16LE<> >(eis); // Parses UTF-16LE file into UTF-8 in memory
fclose(fp); fclose(fp);
``` ~~~~~~~~~~
### EncodedOutputStream ### EncodedOutputStream
`EncodedOutputStream` is similar but it has a `bool putBOM` parameter in the constructor, controlling whether to write BOM into output byte stream. `EncodedOutputStream` is similar but it has a `bool putBOM` parameter in the constructor, controlling whether to write BOM into output byte stream.
```cpp ~~~~~~~~~~cpp
#include "rapidjson/filewritestream.h" // FileWriteStream #include "rapidjson/filewritestream.h" // FileWriteStream
#include "rapidjson/encodedstream.h" // EncodedOutputStream #include "rapidjson/encodedstream.h" // EncodedOutputStream
#include <cstdio> #include <cstdio>
...@@ -174,7 +174,7 @@ Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos); ...@@ -174,7 +174,7 @@ Writer<OutputStream, UTF32LE<>, UTF8<>> writer(eos);
d.Accept(writer); // This generates UTF32-LE file from UTF-8 in memory d.Accept(writer); // This generates UTF32-LE file from UTF-8 in memory
fclose(fp); fclose(fp);
``` ~~~~~~~~~~
### AutoUTFInputStream ### AutoUTFInputStream
...@@ -182,7 +182,7 @@ Sometimes an application may want to handle all supported JSON encoding. `AutoUT ...@@ -182,7 +182,7 @@ Sometimes an application may want to handle all supported JSON encoding. `AutoUT
Since the characters (code units) may be 8-bit, 16-bit or 32-bit. `AutoUTFInputStream` requires a character type which can hold at least 32-bit. We may use `unsigned`, as in the template parameter: Since the characters (code units) may be 8-bit, 16-bit or 32-bit. `AutoUTFInputStream` requires a character type which can hold at least 32-bit. We may use `unsigned`, as in the template parameter:
```cpp ~~~~~~~~~~cpp
#include "rapidjson/document.h" #include "rapidjson/document.h"
#include "rapidjson/filereadstream.h" // FileReadStream #include "rapidjson/filereadstream.h" // FileReadStream
#include "rapidjson/encodedstream.h" // AutoUTFInputStream #include "rapidjson/encodedstream.h" // AutoUTFInputStream
...@@ -201,7 +201,7 @@ Document d; // Document is GenericDocument<UTF8<> > ...@@ -201,7 +201,7 @@ Document d; // Document is GenericDocument<UTF8<> >
d.ParseStream<0, AutoUTF<unsigned> >(eis); // This parses any UTF file into UTF-8 in memory d.ParseStream<0, AutoUTF<unsigned> >(eis); // This parses any UTF file into UTF-8 in memory
fclose(fp); fclose(fp);
``` ~~~~~~~~~~
When specifying the encoding of stream, uses `AutoUTF<CharType>` as in `ParseStream()` above. When specifying the encoding of stream, uses `AutoUTF<CharType>` as in `ParseStream()` above.
...@@ -211,7 +211,7 @@ You can obtain the type of UTF via `UTFType GetType()`. And check whether a BOM ...@@ -211,7 +211,7 @@ You can obtain the type of UTF via `UTFType GetType()`. And check whether a BOM
Similarly, to choose encoding for output during runtime, we can use `AutoUTFOutputStream`. This class is not automatic *per se*. You need to specify the UTF type and whether to write BOM in runtime. Similarly, to choose encoding for output during runtime, we can use `AutoUTFOutputStream`. This class is not automatic *per se*. You need to specify the UTF type and whether to write BOM in runtime.
```cpp ~~~~~~~~~~cpp
void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) { void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) {
char writeBuffer[256]; char writeBuffer[256];
FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer)); FileWriteStream bos(fp, writeBuffer, sizeof(writeBuffer));
...@@ -222,7 +222,7 @@ void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) { ...@@ -222,7 +222,7 @@ void WriteJSONFile(FILE* fp, UTFType type, bool putBOM, const Document& d) {
Writer<OutputStream, UTF8<>, AutoUTF<> > writer; Writer<OutputStream, UTF8<>, AutoUTF<> > writer;
d.Accept(writer); d.Accept(writer);
} }
``` ~~~~~~~~~~
`AutoUTFInputStream` and `AutoUTFOutputStream` is more convenient than `EncodedInputStream` and `EncodedOutputStream`. They just incur a little bit runtime overheads. `AutoUTFInputStream` and `AutoUTFOutputStream` is more convenient than `EncodedInputStream` and `EncodedOutputStream`. They just incur a little bit runtime overheads.
...@@ -232,7 +232,7 @@ In addition to memory/file streams, user can create their own stream classes whi ...@@ -232,7 +232,7 @@ In addition to memory/file streams, user can create their own stream classes whi
RapidJSON combines different types using templates. A class containing all required interface can be a stream. The Stream interface is defined in comments of `rapidjson/rapidjson.h`: RapidJSON combines different types using templates. A class containing all required interface can be a stream. The Stream interface is defined in comments of `rapidjson/rapidjson.h`:
```cpp ~~~~~~~~~~cpp
concept Stream { concept Stream {
typename Ch; //!< Character type of the stream. typename Ch; //!< Character type of the stream.
...@@ -261,7 +261,7 @@ concept Stream { ...@@ -261,7 +261,7 @@ concept Stream {
//! \return Number of characters written. //! \return Number of characters written.
size_t PutEnd(Ch* begin); size_t PutEnd(Ch* begin);
} }
``` ~~~~~~~~~~
For input stream, they must implement `Peek()`, `Take()` and `Tell()`. For input stream, they must implement `Peek()`, `Take()` and `Tell()`.
For output stream, they must implement `Put()` and `Flush()`. For output stream, they must implement `Put()` and `Flush()`.
...@@ -271,7 +271,7 @@ There are two special interface, `PutBegin()` and `PutEnd()`, which are only for ...@@ -271,7 +271,7 @@ There are two special interface, `PutBegin()` and `PutEnd()`, which are only for
The following example is a wrapper of `std::istream`, which only implements 3 functions. The following example is a wrapper of `std::istream`, which only implements 3 functions.
```cpp ~~~~~~~~~~cpp
class IStreamWrapper { class IStreamWrapper {
public: public:
typedef char Ch; typedef char Ch;
...@@ -302,18 +302,18 @@ private: ...@@ -302,18 +302,18 @@ private:
std::istream& is_; std::istream& is_;
}; };
``` ~~~~~~~~~~
User can use it to wrap instances of `std::stringstream`, `std::ifstream`. User can use it to wrap instances of `std::stringstream`, `std::ifstream`.
```cpp ~~~~~~~~~~cpp
const char* json = "[1,2,3,4]"; const char* json = "[1,2,3,4]";
std::stringstream ss(json); std::stringstream ss(json);
IStreamWrapper is(ss); IStreamWrapper is(ss);
Document d; Document d;
d.Parse(is); d.Parse(is);
``` ~~~~~~~~~~
Note that, this implementation may not be as efficient as RapidJSON's memory or file streams, due to internal overheads of the standard library. Note that, this implementation may not be as efficient as RapidJSON's memory or file streams, due to internal overheads of the standard library.
...@@ -321,7 +321,7 @@ Note that, this implementation may not be as efficient as RapidJSON's memory or ...@@ -321,7 +321,7 @@ Note that, this implementation may not be as efficient as RapidJSON's memory or
The following example is a wrapper of `std::istream`, which only implements 2 functions. The following example is a wrapper of `std::istream`, which only implements 2 functions.
```cpp ~~~~~~~~~~cpp
class OStreamWrapper { class OStreamWrapper {
public: public:
typedef char Ch; typedef char Ch;
...@@ -344,11 +344,11 @@ private: ...@@ -344,11 +344,11 @@ private:
std::ostream& os_; std::ostream& os_;
}; };
``` ~~~~~~~~~~
User can use it to wrap instances of `std::stringstream`, `std::ofstream`. User can use it to wrap instances of `std::stringstream`, `std::ofstream`.
```cpp ~~~~~~~~~~cpp
Document d; Document d;
// ... // ...
...@@ -357,7 +357,7 @@ OSStreamWrapper os(ss); ...@@ -357,7 +357,7 @@ OSStreamWrapper os(ss);
Writer<OStreamWrapper> writer(os); Writer<OStreamWrapper> writer(os);
d.Accept(writer); d.Accept(writer);
``` ~~~~~~~~~~
Note that, this implementation may not be as efficient as RapidJSON's memory or file streams, due to internal overheads of the standard library. Note that, this implementation may not be as efficient as RapidJSON's memory or file streams, due to internal overheads of the standard library.
......
...@@ -2,18 +2,18 @@ ...@@ -2,18 +2,18 @@
This tutorial introduces the basics of the Document Object Model(DOM) API. This tutorial introduces the basics of the Document Object Model(DOM) API.
As shown in [Usage at a glance](../readme.md#usage-at-a-glance), a JSON text can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON text. As shown in [Usage at a glance](../readme.md#usage-at-a-glance), a JSON can be parsed into DOM, and then the DOM can be queried and modified easily, and finally be converted back to JSON.
## Value & Document ## Value & Document
Each JSON value is stored in a type called `Value`. A `Document`, representing the DOM, contains the root of `Value`. Each JSON value is stored in a type called `Value`. A `Document`, representing the DOM, contains the root of `Value`. All public types and functions of RapidJSON are defined in the `rapidjson` namespace.
### Query Value ### Query Value
In this section, we will use excerpt of [`example/tutorial/tutorial.cpp`](../example/tutorial/tutorial.cpp). In this section, we will use excerpt of [`example/tutorial/tutorial.cpp`](../example/tutorial/tutorial.cpp).
Assumes we have a JSON text stored in a C string (`const char* json`): Assumes we have a JSON stored in a C string (`const char* json`):
```js ~~~~~~~~~~js
{ {
"hello": "world", "hello": "world",
"t": true , "t": true ,
...@@ -23,10 +23,10 @@ Assumes we have a JSON text stored in a C string (`const char* json`): ...@@ -23,10 +23,10 @@ Assumes we have a JSON text stored in a C string (`const char* json`):
"pi": 3.1416, "pi": 3.1416,
"a": [1, 2, 3, 4] "a": [1, 2, 3, 4]
} }
``` ~~~~~~~~~~
Parse it into a `Document` Parse it into a `Document`
```cpp ~~~~~~~~~~cpp
#include "rapidjson/document.h" #include "rapidjson/document.h"
using namespace rapidjson; using namespace rapidjson;
...@@ -34,50 +34,50 @@ using namespace rapidjson; ...@@ -34,50 +34,50 @@ using namespace rapidjson;
// ... // ...
Document document; Document document;
document.Parse(json); document.Parse(json);
``` ~~~~~~~~~~
The JSON text is now parsed into `document` as a *DOM tree*: The JSON is now parsed into `document` as a *DOM tree*:
![tutorial](diagram/tutorial.png?raw=true) ![tutorial](diagram/tutorial.png)
The root of a conforming JSON should be either an object or an array. In this case, the root is an object. The root of a conforming JSON should be either an object or an array. In this case, the root is an object.
```cpp ~~~~~~~~~~cpp
assert(document.IsObject()); assert(document.IsObject());
``` ~~~~~~~~~~
Query whether a `"hello"` member exists in the root object. Since a `Value` can contain different types of value, we may need to verify its type and use suitable API to obtain the value. In this example, `"hello"` member associates with a JSON string. Query whether a `"hello"` member exists in the root object. Since a `Value` can contain different types of value, we may need to verify its type and use suitable API to obtain the value. In this example, `"hello"` member associates with a JSON string.
```cpp ~~~~~~~~~~cpp
assert(document.HasMember("hello")); assert(document.HasMember("hello"));
assert(document["hello"].IsString()); assert(document["hello"].IsString());
printf("hello = %s\n", document["hello"].GetString()); printf("hello = %s\n", document["hello"].GetString());
``` ~~~~~~~~~~
``` ~~~~~~~~~~
world world
``` ~~~~~~~~~~
JSON true/false values are represented as `bool`. JSON true/false values are represented as `bool`.
```cpp ~~~~~~~~~~cpp
assert(document["t"].IsBool()); assert(document["t"].IsBool());
printf("t = %s\n", document["t"].GetBool() ? "true" : "false"); printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
``` ~~~~~~~~~~
``` ~~~~~~~~~~
true true
``` ~~~~~~~~~~
JSON null can be queryed by `IsNull()`. JSON null can be queryed by `IsNull()`.
```cpp ~~~~~~~~~~cpp
printf("n = %s\n", document["n"].IsNull() ? "null" : "?"); printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
``` ~~~~~~~~~~
``` ~~~~~~~~~~
null null
``` ~~~~~~~~~~
JSON number type represents all numeric values. However, C++ needs more specific type for manipulation. JSON number type represents all numeric values. However, C++ needs more specific type for manipulation.
```cpp ~~~~~~~~~~cpp
assert(document["i"].IsNumber()); assert(document["i"].IsNumber());
// In this case, IsUint()/IsInt64()/IsUInt64() also return true. // In this case, IsUint()/IsInt64()/IsUInt64() also return true.
...@@ -88,28 +88,28 @@ printf("i = %d\n", document["i"].GetInt()); ...@@ -88,28 +88,28 @@ printf("i = %d\n", document["i"].GetInt());
assert(document["pi"].IsNumber()); assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble()); assert(document["pi"].IsDouble());
printf("pi = %g\n", document["pi"].GetDouble()); printf("pi = %g\n", document["pi"].GetDouble());
``` ~~~~~~~~~~
``` ~~~~~~~~~~
i = 123 i = 123
pi = 3.1416 pi = 3.1416
``` ~~~~~~~~~~
JSON array contains a number of elements. JSON array contains a number of elements.
```cpp ~~~~~~~~~~cpp
// Using a reference for consecutive access is handy and faster. // Using a reference for consecutive access is handy and faster.
const Value& a = document["a"]; const Value& a = document["a"];
assert(a.IsArray()); assert(a.IsArray());
for (SizeType i = 0; i < a.Size(); i++) // Uses SizeType instead of size_t for (SizeType i = 0; i < a.Size(); i++) // Uses SizeType instead of size_t
printf("a[%d] = %d\n", i, a[i].GetInt()); printf("a[%d] = %d\n", i, a[i].GetInt());
``` ~~~~~~~~~~
``` ~~~~~~~~~~
a[0] = 1 a[0] = 1
a[1] = 2 a[1] = 2
a[2] = 3 a[2] = 3
a[3] = 4 a[3] = 4
``` ~~~~~~~~~~
Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined. Note that, RapidJSON does not automatically convert values between JSON types. If a value is a string, it is invalid to call `GetInt()`, for example. In debug mode it will fail an assertion. In release mode, the behavior is undefined.
...@@ -124,10 +124,10 @@ You may access the elements in array by integer literal, for example, `a[1]`, `a ...@@ -124,10 +124,10 @@ You may access the elements in array by integer literal, for example, `a[1]`, `a
* `a[0u]` * `a[0u]`
Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements. Array is similar to `std::vector`, instead of using indices, you may also use iterator to access all the elements.
```cpp ~~~~~~~~~~cpp
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
printf("%d ", itr->GetInt()); printf("%d ", itr->GetInt());
``` ~~~~~~~~~~
And other familiar query functions: And other familiar query functions:
* `SizeType Capacity() const` * `SizeType Capacity() const`
...@@ -137,7 +137,7 @@ And other familiar query functions: ...@@ -137,7 +137,7 @@ And other familiar query functions:
Similar to array, we can iterate object members by iterator: Similar to array, we can iterate object members by iterator:
```cpp ~~~~~~~~~~cpp
static const char* kTypeNames[] = static const char* kTypeNames[] =
{ "Null", "False", "True", "Object", "Array", "String", "Number" }; { "Null", "False", "True", "Object", "Array", "String", "Number" };
...@@ -147,9 +147,9 @@ for (Value::ConstMemberIterator itr = document.MemberBegin(); ...@@ -147,9 +147,9 @@ for (Value::ConstMemberIterator itr = document.MemberBegin();
printf("Type of member %s is %s\n", printf("Type of member %s is %s\n",
itr->name.GetString(), kTypeNames[itr->value.GetType()]); itr->name.GetString(), kTypeNames[itr->value.GetType()]);
} }
``` ~~~~~~~~~~
``` ~~~~~~~~~~
Type of member hello is String Type of member hello is String
Type of member t is True Type of member t is True
Type of member f is False Type of member f is False
...@@ -157,17 +157,17 @@ Type of member n is Null ...@@ -157,17 +157,17 @@ Type of member n is Null
Type of member i is Number Type of member i is Number
Type of member pi is Number Type of member pi is Number
Type of member a is Array Type of member a is Array
``` ~~~~~~~~~~
Note that, when `operator[](const char*)` cannot find the member, it will fail an assertion. Note that, when `operator[](const char*)` cannot find the member, it will fail an assertion.
If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain its value at once: If we are unsure whether a member exists, we need to call `HasMember()` before calling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain its value at once:
```cpp ~~~~~~~~~~cpp
Value::ConstMemberIterator itr = document.FindMember("hello"); Value::ConstMemberIterator itr = document.FindMember("hello");
if (itr != document.MemberEnd()) if (itr != document.MemberEnd())
printf("%s %s\n", itr->value.GetString()); printf("%s %s\n", itr->value.GetString());
``` ~~~~~~~~~~
### Querying Number ### Querying Number
...@@ -210,18 +210,18 @@ To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need ...@@ -210,18 +210,18 @@ To conform RFC 4627, RapidJSON supports string containing `U+0000`. If you need
For example, after parsing a the following JSON string to `Document d`. For example, after parsing a the following JSON string to `Document d`.
```js ~~~~~~~~~~js
{ "s" : "a\u0000b" } { "s" : "a\u0000b" }
``` ~~~~~~~~~~
The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1. The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
`GetStringLength()` can also improve performance, as user may often need to call `strlen()` for allocating buffer. `GetStringLength()` can also improve performance, as user may often need to call `strlen()` for allocating buffer.
Besides, `std::string` also support a constructor: Besides, `std::string` also support a constructor:
```cpp ~~~~~~~~~~cpp
string( const char* s, size_type count); string( const char* s, size_type count);
``` ~~~~~~~~~~
which accepts the length of string as parameter. This constructor supports storing null character within the string, and should also provide better performance. which accepts the length of string as parameter. This constructor supports storing null character within the string, and should also provide better performance.
...@@ -232,43 +232,43 @@ There are several ways to create values. After a DOM tree is created and/or modi ...@@ -232,43 +232,43 @@ There are several ways to create values. After a DOM tree is created and/or modi
### Changing Value Type ### Changing Value Type
When creating a Value or Document by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example: When creating a Value or Document by default constructor, its type is Null. To change its type, call `SetXXX()` or assignment operator, for example:
```cpp ~~~~~~~~~~cpp
Document d; // Null Document d; // Null
d.SetObject(); d.SetObject();
Value v; // Null Value v; // Null
v.SetInt(10); v.SetInt(10);
v = 10; // Shortcut, same as above v = 10; // Shortcut, same as above
``` ~~~~~~~~~~
### Overloaded Constructors ### Overloaded Constructors
There are also overloaded constructors for several types: There are also overloaded constructors for several types:
```cpp ~~~~~~~~~~cpp
Value b(true); // calls Value(bool) Value b(true); // calls Value(bool)
Value i(-123); // calls Value(int) Value i(-123); // calls Value(int)
Value u(123u); // calls Value(unsigned) Value u(123u); // calls Value(unsigned)
Value d(1.5); // calls Value(double) Value d(1.5); // calls Value(double)
``` ~~~~~~~~~~
To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one shot: To create empty object or array, you may use `SetObject()`/`SetArray()` after default constructor, or using the `Value(Type)` in one shot:
```cpp ~~~~~~~~~~cpp
Value o(kObjectType); Value o(kObjectType);
Value a(kArrayType); Value a(kArrayType);
``` ~~~~~~~~~~
### Move Semantics ### Move Semantics
A very special decision during design of RapidJSON is that, assignment of value does not copy the source value to destination value. Instead, the value from source is moved to the destination. For example, A very special decision during design of RapidJSON is that, assignment of value does not copy the source value to destination value. Instead, the value from source is moved to the destination. For example,
```cpp ~~~~~~~~~~cpp
Value a(123); Value a(123);
Value b(456); Value b(456);
b = a; // a becomes a Null value, b becomes number 123. b = a; // a becomes a Null value, b becomes number 123.
``` ~~~~~~~~~~
![move1](diagram/move1.png?raw=true) ![move1](diagram/move1.png)
Why? What is the advantage of this semantics? Why? What is the advantage of this semantics?
...@@ -276,7 +276,7 @@ The simple answer is performance. For fixed size JSON types (Number, True, False ...@@ -276,7 +276,7 @@ The simple answer is performance. For fixed size JSON types (Number, True, False
For example, if normal *copy* semantics was used: For example, if normal *copy* semantics was used:
```cpp ~~~~~~~~~~cpp
Value o(kObjectType); Value o(kObjectType);
{ {
Value contacts(kArrayType); Value contacts(kArrayType);
...@@ -285,9 +285,9 @@ Value o(kObjectType); ...@@ -285,9 +285,9 @@ Value o(kObjectType);
o.AddMember("contacts", contacts); // deep clone contacts (may be with lots of allocations) o.AddMember("contacts", contacts); // deep clone contacts (may be with lots of allocations)
// destruct contacts. // destruct contacts.
} }
``` ~~~~~~~~~~
![move2](diagram/move2.png?raw=true) ![move2](diagram/move2.png)
The object `o` needs to allocate a buffer of same size as contacts, makes a deep clone of it, and then finally contacts is destructed. This will incur a lot of unnecessary allocations/deallocations and memory copying. The object `o` needs to allocate a buffer of same size as contacts, makes a deep clone of it, and then finally contacts is destructed. This will incur a lot of unnecessary allocations/deallocations and memory copying.
...@@ -297,7 +297,7 @@ To make RapidJSON simple and fast, we chose to use *move* semantics for assignme ...@@ -297,7 +297,7 @@ To make RapidJSON simple and fast, we chose to use *move* semantics for assignme
So, with move semantics, the above example becomes: So, with move semantics, the above example becomes:
```cpp ~~~~~~~~~~cpp
Value o(kObjectType); Value o(kObjectType);
{ {
Value contacts(kArrayType); Value contacts(kArrayType);
...@@ -305,9 +305,9 @@ Value o(kObjectType); ...@@ -305,9 +305,9 @@ Value o(kObjectType);
o.AddMember("contacts", contacts); // just memcpy() of contacts itself to the value of new member (16 bytes) o.AddMember("contacts", contacts); // just memcpy() of contacts itself to the value of new member (16 bytes)
// contacts became Null here. Its destruction is trivial. // contacts became Null here. Its destruction is trivial.
} }
``` ~~~~~~~~~~
![move3](diagram/move3.png?raw=true) ![move3](diagram/move3.png)
This is called move assignment operator in C++11. As RapidJSON supports C++03, it adopts move semantics using assignment operator, and all other modifying function like `AddMember()`, `PushBack()`. This is called move assignment operator in C++11. As RapidJSON supports C++03, it adopts move semantics using assignment operator, and all other modifying function like `AddMember()`, `PushBack()`.
...@@ -323,7 +323,7 @@ To make memory allocation customizable, RapidJSON requires user to pass an insta ...@@ -323,7 +323,7 @@ To make memory allocation customizable, RapidJSON requires user to pass an insta
Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator: Therefore, when we assign a copy-string, we call this overloaded `SetString()` with allocator:
```cpp ~~~~~~~~~~cpp
Document document; Document document;
Value author; Value author;
char buffer[10]; char buffer[10];
...@@ -331,7 +331,7 @@ int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // dynamically created string ...@@ -331,7 +331,7 @@ int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // dynamically created string
author.SetString(buffer, len, document.GetAllocator()); author.SetString(buffer, len, document.GetAllocator());
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
// author.GetString() still contains "Milo Yip" after buffer is destroyed // author.GetString() still contains "Milo Yip" after buffer is destroyed
``` ~~~~~~~~~~
In this example, we get the allocator from a `Document` instance. This is a common idiom when using RapidJSON. But you may use other instances of allocator. In this example, we get the allocator from a `Document` instance. This is a common idiom when using RapidJSON. But you may use other instances of allocator.
...@@ -339,12 +339,12 @@ Besides, the above `SetString()` requires length. This can handle null character ...@@ -339,12 +339,12 @@ Besides, the above `SetString()` requires length. This can handle null character
Finally, for literal string or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter: Finally, for literal string or string with safe life-cycle can use const-string version of `SetString()`, which lacks allocator parameter:
```cpp ~~~~~~~~~~cpp
Value s; Value s;
s.SetString("rapidjson", 9); // faster, can contain null character s.SetString("rapidjson", 9); // faster, can contain null character
s.SetString("rapidjson"); // slower, assumes null-terminated s.SetString("rapidjson"); // slower, assumes null-terminated
s = "rapidjson"; // shortcut, same as above s = "rapidjson"; // shortcut, same as above
``` ~~~~~~~~~~
### Modify Array ### Modify Array
Value with array type provides similar APIs as `std::vector`. Value with array type provides similar APIs as `std::vector`.
...@@ -359,7 +359,7 @@ Note that, `Reserve(...)` and `PushBack(...)` may allocate memory, therefore req ...@@ -359,7 +359,7 @@ Note that, `Reserve(...)` and `PushBack(...)` may allocate memory, therefore req
Here is an example of `PushBack()`: Here is an example of `PushBack()`:
```cpp ~~~~~~~~~~cpp
Value a(kArrayType); Value a(kArrayType);
Document::AllocatorType& allocator = document.GetAllocator(); Document::AllocatorType& allocator = document.GetAllocator();
...@@ -368,7 +368,7 @@ for (int i = 5; i <= 10; i++) ...@@ -368,7 +368,7 @@ for (int i = 5; i <= 10; i++)
// Fluent interface // Fluent interface
a.PushBack("Lua", allocator).PushBack("Mio", allocator); a.PushBack("Lua", allocator).PushBack("Mio", allocator);
``` ~~~~~~~~~~
Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called fluent interface. Differs from STL, `PushBack()`/`PopBack()` returns the array reference itself. This is called fluent interface.
...@@ -382,16 +382,16 @@ Object is a collection of key-value pairs. Each key must be a string value. The ...@@ -382,16 +382,16 @@ Object is a collection of key-value pairs. Each key must be a string value. The
Here is an example. Here is an example.
```cpp ~~~~~~~~~~cpp
Value contact(kObejct); Value contact(kObejct);
contact.AddMember("name", "Milo", document.GetAllocator()); contact.AddMember("name", "Milo", document.GetAllocator());
contact.AddMember("married", true, document.GetAllocator()); contact.AddMember("married", true, document.GetAllocator());
``` ~~~~~~~~~~
### Deep Copy Value ### Deep Copy Value
If we really need to copy a DOM tree, we can use two APIs for deep copy: constructor with allocator, and `CopyFrom()`. If we really need to copy a DOM tree, we can use two APIs for deep copy: constructor with allocator, and `CopyFrom()`.
```cpp ~~~~~~~~~~cpp
Document d; Document d;
Document::AllocatorType& a = d.GetAllocator(); Document::AllocatorType& a = d.GetAllocator();
Value v1("foo"); Value v1("foo");
...@@ -406,19 +406,19 @@ v2.CopyFrom(d, a); // copy whole document to v2 ...@@ -406,19 +406,19 @@ v2.CopyFrom(d, a); // copy whole document to v2
assert(d.IsArray() && d.Size() == 2); // d untouched assert(d.IsArray() && d.Size() == 2); // d untouched
v1.SetObject().AddMember( "array", v2, a ); v1.SetObject().AddMember( "array", v2, a );
d.PushBack(v1,a); d.PushBack(v1,a);
``` ~~~~~~~~~~
### Swap Values ### Swap Values
`Swap()` is also provided. `Swap()` is also provided.
```cpp ~~~~~~~~~~cpp
Value a(123); Value a(123);
Value b("Hello"); Value b("Hello");
a.Swap(b); a.Swap(b);
assert(a.IsString()); assert(a.IsString());
assert(b.IsInt()); assert(b.IsInt());
``` ~~~~~~~~~~
Swapping two DOM trees is fast (constant time), despite the complexity of the tress. Swapping two DOM trees is fast (constant time), despite the complexity of the tress.
......
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