Commit cec8dcbc authored by Milo Yip's avatar Milo Yip

Add optional unresolvedTokenIndex parameter to Pointer::Get() and related

parent e702d3dc
...@@ -460,9 +460,18 @@ public: ...@@ -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: ...@@ -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: ...@@ -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 ...@@ -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) { ...@@ -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) { ...@@ -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) {
......
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