Commit 98928470 authored by Milo Yip's avatar Milo Yip

Update documents about erase member/elements, also added some time complexity information.

parent 10098319
......@@ -222,11 +222,26 @@ The correct length of the value `"a\u0000b"` is 3. But `strlen()` returns 1.
Besides, `std::string` also support a constructor:
~~~~~~~~~~cpp
string( const char* s, size_type count);
string(const char* s, size_t count);
~~~~~~~~~~
which accepts the length of string as parameter. This constructor supports storing null character within the string, and should also provide better performance.
## Comparing values
You can use `==` and `!=` to compare values. Two values are equal if and only if they are have same type and contents. You can also compare values with primitive types. Here is an example.
~~~~~~~~~~cpp
if (document["hello"] == document["n"]) /*...*/; // Compare values
if (document["hello"] == "world") /*...*/; // Compare value with literal string
if (document["i"] != 123) /*...*/; // Compare with integers
if (document["pi"] != 3.14) /*...*/; // Compare with double.
~~~~~~~~~~
Array and object must be `Value`s in order to be compared. They are equal if and only if their whole subtrees are equal.
Note that, currently if an object contains duplicated named member, comparing equality with any object is always `false`.
# Create/Modify Values {#CreateModifyValues}
There are several ways to create values. After a DOM tree is created and/or modified, it can be saved as JSON again using `Writer`.
......@@ -380,6 +395,8 @@ Value with array type provides similar APIs as `std::vector`.
* `Value& PushBack(Value&, Allocator&)`
* `template <typename T> GenericValue& PushBack(T, Allocator&)`
* `Value& PopBack()`
* `ValueIterator Erase(ConstValueIterator pos)`
* `ValueIterator Erase(ConstValueIterator first, ConstValueIterator last)`
Note that, `Reserve(...)` and `PushBack(...)` may allocate memory for the array elements, therefore require an allocator.
......@@ -411,12 +428,11 @@ contact.PushBack(val, document.GetAllocator());
~~~~~~~~~~
## Modify Object {#ModifyObject}
Object is a collection of key-value pairs. Each key must be a string value. The way to manipulating object is to add/remove members:
Object is a collection of key-value pairs. Each key must be a string value. The way to manipulating object is to add members:
* `Value& AddMember(Value&, Value&, Allocator& allocator)`
* `Value& AddMember(StringRefType, Value&, Allocator&)`
* `template <typename T> Value& AddMember(StringRefType, T value, Allocator&)`
* `bool RemoveMember(const Ch*)`
Here is an example.
......@@ -442,6 +458,16 @@ Value val(42); // some value
contact.AddMember(key, val, document.GetAllocator());
~~~~~~~~~~
For removing members, there are several choices:
* `bool RemoveMember(const Ch* name)`: Remove a member by search its name (linear time complexity).
* `bool RemoveMember(const Value& name)`: same as above but `name` is a Value.
* `MemberIterator RemoveMember(MemberIterator)`: Remove a member by iterator (_constant_ time complexity).
* `MemberIterator EraseMember(MemberIterator)`: similar to the above but it preserves order of members (linear time complexity).
* `MemberIterator EraseMember(MemberIterator first, MemberIterator last)`: remove a range of members, preserves order (linear time complexity).
`MemberIterator RemoveMember(MemberIterator)` uses a "move-last" trick to archive constant time complexity. Basically the member at iterator is destructed, and then the last element is moved to that position. So the order of the remaining members are changed.
## Deep Copy Value {#DeepCopyValue}
If we really need to copy a DOM tree, we can use two APIs for deep copy: constructor with allocator, and `CopyFrom()`.
......@@ -458,8 +484,8 @@ assert(v1.IsNull() && v2.IsNull()); // both moved to d
v2.CopyFrom(d, a); // copy whole document to v2
assert(d.IsArray() && d.Size() == 2); // d untouched
v1.SetObject().AddMember( "array", v2, a );
d.PushBack(v1,a);
v1.SetObject().AddMember("array", v2, a);
d.PushBack(v1, a);
~~~~~~~~~~
## Swap Values {#SwapValues}
......@@ -474,7 +500,7 @@ assert(a.IsString());
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 trees.
# What's next {#WhatsNext}
......
......@@ -558,6 +558,10 @@ public:
//!@name Equal-to and not-equal-to operators
//@{
//! Equal-to operator
/*!
\note If an object contains duplicated named member, comparing equality with any object is always \c false.
\note Linear time complexity (number of all values in the subtree and total lengths of all strings).
*/
bool operator==(const GenericValue& rhs) const {
if (GetType() != rhs.GetType())
return false;
......@@ -572,7 +576,6 @@ public:
return false;
}
return true;
case kArrayType:
if (data_.a.size != rhs.data_.a.size)
......@@ -669,7 +672,8 @@ public:
\note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
Since 0.2, if the name is not correct, it will assert.
If user is unsure whether a member exists, user should use HasMember() first.
A better approach is to use the now public FindMember().
A better approach is to use FindMember().
\note Linear time complexity.
*/
GenericValue& operator[](const Ch* name) {
GenericValue n(StringRef(name));
......@@ -706,16 +710,28 @@ public:
//! Check whether a member exists in the object.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Whether a member with that name exists.
\note It is better to use FindMember() directly if you need the obtain the value as well.
\note Linear time complexity.
*/
bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
// This version is faster because it does not need a StrLen().
// It can also handle string with null character.
//! Check whether a member exists in the object with GenericValue name.
/*!
This version is faster because it does not need a StrLen(). It can also handle string with null character.
\param name Member name to be searched.
\pre IsObject() == true
\return Whether a member with that name exists.
\note It is better to use FindMember() directly if you need the obtain the value as well.
\note Linear time complexity.
*/
bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); }
//! Find member by name.
/*!
\param name Member name to be searched.
\pre IsObject() == true
\return Iterator to member, if it exists.
Otherwise returns \ref MemberEnd().
......@@ -723,6 +739,7 @@ public:
\note Earlier versions of Rapidjson returned a \c NULL pointer, in case
the requested member doesn't exist. For consistency with e.g.
\c std::map, this has been changed to MemberEnd() now.
\note Linear time complexity.
*/
MemberIterator FindMember(const Ch* name) {
GenericValue n(StringRef(name));
......@@ -731,8 +748,19 @@ public:
ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
// This version is faster because it does not need a StrLen().
// It can also handle string with null character.
//! Find member by name.
/*!
This version is faster because it does not need a StrLen(). It can also handle string with null character.
\param name Member name to be searched.
\pre IsObject() == true
\return Iterator to member, if it exists.
Otherwise returns \ref MemberEnd().
\note Earlier versions of Rapidjson returned a \c NULL pointer, in case
the requested member doesn't exist. For consistency with e.g.
\c std::map, this has been changed to MemberEnd() now.
\note Linear time complexity.
*/
MemberIterator FindMember(const GenericValue& name) {
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
......@@ -752,6 +780,7 @@ public:
\note The ownership of \c name and \c value will be transferred to this object on success.
\pre IsObject() && name.IsString()
\post name.IsNull() && value.IsNull()
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsObject());
......@@ -783,6 +812,7 @@ public:
\note The ownership of \c value will be transferred to this object on success.
\pre IsObject()
\post value.IsNull()
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
GenericValue n(name);
......@@ -796,6 +826,7 @@ public:
\return The value itself for fluent API.
\pre IsObject()
\note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
\note Amortized Constant time complexity.
*/
GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
GenericValue v(value);
......@@ -817,6 +848,7 @@ public:
AddMember(StringRefType, StringRefType, Allocator&).
All other pointer types would implicitly convert to \c bool,
use an explicit cast instead, if needed.
\note Amortized Constant time complexity.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
......@@ -830,6 +862,7 @@ public:
/*! \param name Name of member to be removed.
\return Whether the member existed.
\note Removing member is implemented by moving the last member. So the ordering of members is changed.
\note Linear time complexity.
*/
bool RemoveMember(const Ch* name) {
GenericValue n(StringRef(name));
......@@ -851,6 +884,7 @@ public:
\return the new iterator after removal.
\note Removing member is implemented by moving the last member. So the ordering of members is changed.
\note Use \ref EraseMember(ConstMemberIterator) instead, if you need to rely on a stable member ordering.
\note Constant time complexity.
*/
MemberIterator RemoveMember(MemberIterator m) {
RAPIDJSON_ASSERT(IsObject());
......@@ -877,6 +911,7 @@ public:
\return Iterator following the removed element.
If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
\note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members.
\note Linear time complexity.
*/
MemberIterator EraseMember(ConstMemberIterator pos) {
return EraseMember(pos, pos +1);
......@@ -888,6 +923,7 @@ public:
\pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
\return Iterator following the last removed element.
\note Other than \ref RemoveMember(MemberIterator), this function preserves the ordering of the members.
\note Linear time complexity.
*/
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
RAPIDJSON_ASSERT(IsObject());
......@@ -925,6 +961,7 @@ public:
//! Remove all elements in the array.
/*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
\note Linear time complexity.
*/
void Clear() {
RAPIDJSON_ASSERT(IsArray());
......@@ -967,6 +1004,7 @@ int z = a[0u].GetInt(); // This works too.
/*! \param newCapacity The capacity that the array at least need to have.
\param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
\return The value itself for fluent API.
\note Linear time complexity.
*/
GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
RAPIDJSON_ASSERT(IsArray());
......@@ -985,6 +1023,7 @@ int z = a[0u].GetInt(); // This works too.
\return The value itself for fluent API.
\note The ownership of \c value will be transferred to this array on success.
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
\note Amortized constant time complexity.
*/
GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
RAPIDJSON_ASSERT(IsArray());
......@@ -1000,6 +1039,7 @@ int z = a[0u].GetInt(); // This works too.
\pre IsArray() == true
\return The value itself for fluent API.
\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
\note Amortized constant time complexity.
\see GenericStringRef
*/
GenericValue& PushBack(StringRefType value, Allocator& allocator) {
......@@ -1021,6 +1061,7 @@ int z = a[0u].GetInt(); // This works too.
PushBack(StringRefType, Allocator&).
All other pointer types would implicitly convert to \c bool,
use an explicit cast instead, if needed.
\note Amortized constant time complexity.
*/
template <typename T>
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
......@@ -1030,6 +1071,9 @@ int z = a[0u].GetInt(); // This works too.
}
//! Remove the last element in the array.
/*!
\note Constant time complexity.
*/
GenericValue& PopBack() {
RAPIDJSON_ASSERT(IsArray());
RAPIDJSON_ASSERT(!Empty());
......@@ -1042,6 +1086,7 @@ int z = a[0u].GetInt(); // This works too.
\param pos iterator to the element to remove
\pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
\return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
\note Linear time complexity.
*/
ValueIterator Erase(ConstValueIterator pos) {
return Erase(pos, pos + 1);
......@@ -1053,6 +1098,7 @@ int z = a[0u].GetInt(); // This works too.
\param last iterator following the last element to remove
\pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
\return Iterator following the last removed element.
\note Linear time complexity.
*/
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
RAPIDJSON_ASSERT(IsArray());
......
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