tutorial.md: prepare Markdown for GitHub and Doxygen rendering
This commit is contained in:
parent
2a57d97f63
commit
ba05cc1377
136
doc/tutorial.md
136
doc/tutorial.md
@ -13,7 +13,7 @@ Each JSON value is stored in a type called `Value`. A `Document`, representing t
|
|||||||
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 text 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`):
|
|||||||
"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;
|
|||||||
// ...
|
// ...
|
||||||
Document document;
|
Document document;
|
||||||
document.Parse(json);
|
document.Parse(json);
|
||||||
```
|
~~~~~~~~~~
|
||||||
|
|
||||||
The JSON text is now parsed into `document` as a *DOM tree*:
|
The JSON text is now parsed into `document` as a *DOM tree*:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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());
|
|||||||
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
|
|||||||
* `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:
|
|||||||
|
|
||||||
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();
|
|||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
### 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.
|
||||||
```
|
~~~~~~~~~~
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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);
|
|||||||
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.
|
||||||
}
|
}
|
||||||
```
|
~~~~~~~~~~
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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);
|
|||||||
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.
|
||||||
}
|
}
|
||||||
```
|
~~~~~~~~~~
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
|
|
||||||
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++)
|
|||||||
|
|
||||||
// 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
|
|||||||
|
|
||||||
Here is an example.
|
Here is an example.
|
||||||
|
|
||||||
```cpp
|
~~~~~~~~~~cpp
|
||||||
Value contact(kObejct);
|
Value contact(kObject);
|
||||||
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
|
|||||||
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.
|
||||||
|
|
||||||
@ -433,4 +433,4 @@ This tutorial shows the basics of DOM tree query and manipulation. There are sev
|
|||||||
5. [Performance](performance.md) shows some in-house and third-party benchmarks.
|
5. [Performance](performance.md) shows some in-house and third-party benchmarks.
|
||||||
6. [Internals](internals.md) describes some internal designs and techniques of RapidJSON.
|
6. [Internals](internals.md) describes some internal designs and techniques of RapidJSON.
|
||||||
|
|
||||||
You may also refer to the FAQ, API documentation, examples and unit tests.
|
You may also refer to the [FAQ](faq.md), API documentation, examples and unit tests.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user