mirror of
				https://github.com/Tencent/rapidjson.git
				synced 2025-10-28 11:31:57 +01:00 
			
		
		
		
	Add optional unresolvedTokenIndex parameter to Pointer::Get() and related
This commit is contained in:
		| @@ -460,9 +460,18 @@ public: | |||||||
|     //! Query a value in a subtree. |     //! Query a value in a subtree. | ||||||
|     /*! |     /*! | ||||||
|         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. |         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. | ||||||
|  |         \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. | ||||||
|         \return Pointer to the value if it can be resolved. Otherwise null. |         \return Pointer to the value if it can be resolved. Otherwise null. | ||||||
|  |  | ||||||
|  |         \note | ||||||
|  |         There are only 3 situations when a value cannot be resolved: | ||||||
|  |         1. A value in the path is not an array nor object. | ||||||
|  |         2. An object value does not contain the token. | ||||||
|  |         3. A token is out of range of an array value. | ||||||
|  |  | ||||||
|  |         Use unresolvedTokenIndex to retrieve the token index. | ||||||
|     */ |     */ | ||||||
|     ValueType* Get(ValueType& root) const { |     ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { | ||||||
|         RAPIDJSON_ASSERT(IsValid()); |         RAPIDJSON_ASSERT(IsValid()); | ||||||
|         ValueType* v = &root; |         ValueType* v = &root; | ||||||
|         for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { |         for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { | ||||||
| @@ -471,18 +480,23 @@ public: | |||||||
|                 { |                 { | ||||||
|                     typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length)); |                     typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length)); | ||||||
|                     if (m == v->MemberEnd()) |                     if (m == v->MemberEnd()) | ||||||
|                         return 0; |                         break; | ||||||
|                     v = &m->value; |                     v = &m->value; | ||||||
|                 } |                 } | ||||||
|                 break; |                 continue; | ||||||
|             case kArrayType: |             case kArrayType: | ||||||
|                 if (t->index == kPointerInvalidIndex || t->index >= v->Size()) |                 if (t->index == kPointerInvalidIndex || t->index >= v->Size()) | ||||||
|                     return 0; |                     break; | ||||||
|                 v = &((*v)[t->index]); |                 v = &((*v)[t->index]); | ||||||
|                 break; |                 continue; | ||||||
|             default: |             default: | ||||||
|                 return 0; |                 break; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // Error: unresolved token | ||||||
|  |             if (unresolvedTokenIndex) | ||||||
|  |                 *unresolvedTokenIndex = static_cast<size_t>(t - tokens_); | ||||||
|  |             return 0; | ||||||
|         } |         } | ||||||
|         return v; |         return v; | ||||||
|     } |     } | ||||||
| @@ -492,7 +506,9 @@ public: | |||||||
|         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. |         \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. | ||||||
|         \return Pointer to the value if it can be resolved. Otherwise null. |         \return Pointer to the value if it can be resolved. Otherwise null. | ||||||
|     */ |     */ | ||||||
|     const ValueType* Get(const ValueType& root) const { return Get(const_cast<ValueType&>(root)); } |     const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {  | ||||||
|  |         return Get(const_cast<ValueType&>(root), unresolvedTokenIndex); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     //@} |     //@} | ||||||
|  |  | ||||||
| @@ -1053,23 +1069,23 @@ typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, c | |||||||
| ////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
| template <typename T> | template <typename T> | ||||||
| typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) { | typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) { | ||||||
|     return pointer.Get(root); |     return pointer.Get(root, unresolvedTokenIndex); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename T> | template <typename T> | ||||||
| const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer) { | const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) { | ||||||
|     return pointer.Get(root); |     return pointer.Get(root, unresolvedTokenIndex); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename T, typename CharType, size_t N> | template <typename T, typename CharType, size_t N> | ||||||
| typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) { | typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { | ||||||
|     return GenericPointer<typename T::ValueType>(source, N - 1).Get(root); |     return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename T, typename CharType, size_t N> | template <typename T, typename CharType, size_t N> | ||||||
| const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) { | const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { | ||||||
|     return GenericPointer<typename T::ValueType>(source, N - 1).Get(root); |     return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex); | ||||||
| } | } | ||||||
|  |  | ||||||
| ////////////////////////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////////////////////////// | ||||||
|   | |||||||
| @@ -627,10 +627,15 @@ TEST(Pointer, Get) { | |||||||
|     EXPECT_EQ(&d[" "], Pointer("/ ").Get(d)); |     EXPECT_EQ(&d[" "], Pointer("/ ").Get(d)); | ||||||
|     EXPECT_EQ(&d["m~n"], Pointer("/m~0n").Get(d)); |     EXPECT_EQ(&d["m~n"], Pointer("/m~0n").Get(d)); | ||||||
|     EXPECT_TRUE(Pointer("/abc").Get(d) == 0); |     EXPECT_TRUE(Pointer("/abc").Get(d) == 0); | ||||||
|     EXPECT_TRUE(Pointer("/foo/2").Get(d) == 0); // Out of boundary |     size_t unresolvedTokenIndex; | ||||||
|     EXPECT_TRUE(Pointer("/foo/a").Get(d) == 0); // "/foo" is an array, cannot query by "a" |     EXPECT_TRUE(Pointer("/foo/2").Get(d, &unresolvedTokenIndex) == 0); // Out of boundary | ||||||
|     EXPECT_TRUE(Pointer("/foo/0/0").Get(d) == 0); // "/foo/0" is an string, cannot further query |     EXPECT_EQ(1, unresolvedTokenIndex); | ||||||
|     EXPECT_TRUE(Pointer("/foo/0/a").Get(d) == 0); // "/foo/0" is an string, cannot further query |     EXPECT_TRUE(Pointer("/foo/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a" | ||||||
|  |     EXPECT_EQ(1, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(Pointer("/foo/0/0").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query | ||||||
|  |     EXPECT_EQ(2, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(Pointer("/foo/0/a").Get(d, &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query | ||||||
|  |     EXPECT_EQ(2, unresolvedTokenIndex); | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Pointer, GetWithDefault) { | TEST(Pointer, GetWithDefault) { | ||||||
| @@ -947,10 +952,30 @@ TEST(Pointer, GetValueByPointer) { | |||||||
|     EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, Pointer("/foo/0"))); |     EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, Pointer("/foo/0"))); | ||||||
|     EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, "/foo/0")); |     EXPECT_EQ(&d["foo"][0], GetValueByPointer(d, "/foo/0")); | ||||||
|  |  | ||||||
|  |     size_t unresolvedTokenIndex; | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(d, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary | ||||||
|  |     EXPECT_EQ(1, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(d, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a" | ||||||
|  |     EXPECT_EQ(1, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(d, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query | ||||||
|  |     EXPECT_EQ(2, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(d, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query | ||||||
|  |     EXPECT_EQ(2, unresolvedTokenIndex); | ||||||
|  |  | ||||||
|     // const version |     // const version | ||||||
|     const Value& v = d; |     const Value& v = d; | ||||||
|     EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, Pointer("/foo/0"))); |     EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, Pointer("/foo/0"))); | ||||||
|     EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, "/foo/0")); |     EXPECT_EQ(&d["foo"][0], GetValueByPointer(v, "/foo/0")); | ||||||
|  |  | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(v, "/foo/2", &unresolvedTokenIndex) == 0); // Out of boundary | ||||||
|  |     EXPECT_EQ(1, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(v, "/foo/a", &unresolvedTokenIndex) == 0); // "/foo" is an array, cannot query by "a" | ||||||
|  |     EXPECT_EQ(1, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(v, "/foo/0/0", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query | ||||||
|  |     EXPECT_EQ(2, unresolvedTokenIndex); | ||||||
|  |     EXPECT_TRUE(GetValueByPointer(v, "/foo/0/a", &unresolvedTokenIndex) == 0); // "/foo/0" is an string, cannot further query | ||||||
|  |     EXPECT_EQ(2, unresolvedTokenIndex); | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| TEST(Pointer, GetValueByPointerWithDefault_Pointer) { | TEST(Pointer, GetValueByPointerWithDefault_Pointer) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Milo Yip
					Milo Yip