tutorial.md (rapidjson-1.0.2) | : | tutorial.md (rapidjson-1.1.0) | ||
---|---|---|---|---|
skipping to change at line 136 | skipping to change at line 136 | |||
Array is similar to `std::vector`, instead of using indices, you may also use it erator to access all the elements. | Array is similar to `std::vector`, instead of using indices, you may also use it erator 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` | |||
* `bool Empty() const` | * `bool Empty() const` | |||
### Range-based For Loop (New in v1.1.0) | ||||
When C++11 is enabled, you can use range-based for loop to access all elements i | ||||
n an array. | ||||
~~~~~~~~~~cpp | ||||
for (auto& v : a.GetArray()) | ||||
printf("%d ", v.GetInt()); | ||||
~~~~~~~~~~ | ||||
## Query Object {#QueryObject} | ## Query Object {#QueryObject} | |||
Similar to array, we can access all object members by iterator: | Similar to array, we can access all 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" }; | |||
for (Value::ConstMemberIterator itr = document.MemberBegin(); | for (Value::ConstMemberIterator itr = document.MemberBegin(); | |||
itr != document.MemberEnd(); ++itr) | itr != document.MemberEnd(); ++itr) | |||
skipping to change at line 169 | skipping to change at line 178 | |||
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 a n assertion. | Note that, when `operator[](const char*)` cannot find the member, it will fail a n assertion. | |||
If we are unsure whether a member exists, we need to call `HasMember()` before c alling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain it s value at once: | If we are unsure whether a member exists, we need to call `HasMember()` before c alling `operator[](const char*)`. However, this incurs two lookup. A better way is to call `FindMember()`, which can check the existence of member and obtain it s 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\n", itr->value.GetString()); | |||
~~~~~~~~~~ | ||||
### Range-based For Loop (New in v1.1.0) | ||||
When C++11 is enabled, you can use range-based for loop to access all members in | ||||
an object. | ||||
~~~~~~~~~~cpp | ||||
for (auto& m : document.GetObject()) | ||||
printf("Type of member %s is %s\n", | ||||
m.name.GetString(), kTypeNames[m.value.GetType()]); | ||||
~~~~~~~~~~ | ~~~~~~~~~~ | |||
## Querying Number {#QueryNumber} | ## Querying Number {#QueryNumber} | |||
JSON provide a single numerical type called Number. Number can be integer or rea l numbers. RFC 4627 says the range of Number is specified by parser. | JSON provide a single numerical type called Number. Number can be integer or rea l numbers. RFC 4627 says the range of Number is specified by parser. | |||
As C++ provides several integer and floating point number types, the DOM tries t o handle these with widest possible range and good performance. | As C++ provides several integer and floating point number types, the DOM tries t o handle these with widest possible range and good performance. | |||
When a Number is parsed, it is stored in the DOM as either one of the following type: | When a Number is parsed, it is stored in the DOM as either one of the following type: | |||
skipping to change at line 295 | skipping to change at line 314 | |||
 |  | |||
Why? What is the advantage of this semantics? | Why? What is the advantage of this semantics? | |||
The simple answer is performance. For fixed size JSON types (Number, True, False , Null), copying them is fast and easy. However, For variable size JSON types (S tring, Array, Object), copying them will incur a lot of overheads. And these ove rheads are often unnoticed. Especially when we need to create temporary object, copy it to another variable, and then destruct it. | The simple answer is performance. For fixed size JSON types (Number, True, False , Null), copying them is fast and easy. However, For variable size JSON types (S tring, Array, Object), copying them will incur a lot of overheads. And these ove rheads are often unnoticed. Especially when we need to create temporary object, copy it to another variable, and then destruct it. | |||
For example, if normal *copy* semantics was used: | For example, if normal *copy* semantics was used: | |||
~~~~~~~~~~cpp | ~~~~~~~~~~cpp | |||
Document d; | ||||
Value o(kObjectType); | Value o(kObjectType); | |||
{ | { | |||
Value contacts(kArrayType); | Value contacts(kArrayType); | |||
// adding elements to contacts array. | // adding elements to contacts array. | |||
// ... | // ... | |||
o.AddMember("contacts", contacts); // deep clone contacts (may be with lots of allocations) | o.AddMember("contacts", contacts, d.GetAllocator()); // 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. | |||
There are solutions to prevent actual copying these data, such as reference coun ting and garbage collection(GC). | There are solutions to prevent actual copying these data, such as reference coun ting and garbage collection(GC). | |||
To make RapidJSON simple and fast, we chose to use *move* semantics for assignme nt. It is similar to `std::auto_ptr` which transfer ownership during assignment. Move is much faster and simpler, it just destructs the original value, `memcpy( )` the source to destination, and finally sets the source as Null type. | To make RapidJSON simple and fast, we chose to use *move* semantics for assignme nt. It is similar to `std::auto_ptr` which transfer ownership during assignment. Move is much faster and simpler, it just destructs the original value, `memcpy( )` the source to destination, and finally sets the source as Null type. | |||
So, with move semantics, the above example becomes: | So, with move semantics, the above example becomes: | |||
~~~~~~~~~~cpp | ~~~~~~~~~~cpp | |||
Document d; | ||||
Value o(kObjectType); | Value o(kObjectType); | |||
{ | { | |||
Value contacts(kArrayType); | Value contacts(kArrayType); | |||
// adding elements to contacts array. | // adding elements to contacts array. | |||
o.AddMember("contacts", contacts); // just memcpy() of contacts itself to t he value of new member (16 bytes) | o.AddMember("contacts", contacts, d.GetAllocator()); // just memcpy() of co ntacts 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, i t adopts move semantics using assignment operator, and all other modifying funct ion like `AddMember()`, `PushBack()`. | This is called move assignment operator in C++11. As RapidJSON supports C++03, i t adopts move semantics using assignment operator, and all other modifying funct ion like `AddMember()`, `PushBack()`. | |||
### Move semantics and temporary values {#TemporaryValues} | ### Move semantics and temporary values {#TemporaryValues} | |||
End of changes. 6 change blocks. | ||||
3 lines changed or deleted | 26 lines changed or added |