Add Pointer::Append() and fixed bugs in assignment and Parse()
This commit is contained in:
parent
f4e357f65d
commit
5dee394004
@ -16,6 +16,7 @@
|
|||||||
#define RAPIDJSON_POINTER_H_
|
#define RAPIDJSON_POINTER_H_
|
||||||
|
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
|
#include "internal/itoa.h"
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -169,38 +170,109 @@ public:
|
|||||||
|
|
||||||
//! Assignment operator.
|
//! Assignment operator.
|
||||||
GenericPointer& operator=(const GenericPointer& rhs) {
|
GenericPointer& operator=(const GenericPointer& rhs) {
|
||||||
this->~GenericPointer();
|
if (this != &rhs) {
|
||||||
|
// Do not delete ownAllcator
|
||||||
|
if (nameBuffer_) {
|
||||||
|
Allocator::Free(nameBuffer_);
|
||||||
|
Allocator::Free(tokens_);
|
||||||
|
}
|
||||||
|
|
||||||
tokenCount_ = rhs.tokenCount_;
|
tokenCount_ = rhs.tokenCount_;
|
||||||
parseErrorOffset_ = rhs.parseErrorOffset_;
|
parseErrorOffset_ = rhs.parseErrorOffset_;
|
||||||
parseErrorCode_ = rhs.parseErrorCode_;
|
parseErrorCode_ = rhs.parseErrorCode_;
|
||||||
|
|
||||||
if (rhs.nameBuffer_) { // Normally parsed tokens.
|
if (rhs.nameBuffer_)
|
||||||
if (!allocator_) // allocator is independently owned.
|
CopyFromRaw(rhs); // Normally parsed tokens.
|
||||||
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
else {
|
||||||
|
tokens_ = rhs.tokens_; // User supplied const tokens.
|
||||||
size_t nameBufferSize = tokenCount_; // null terminators for tokens
|
nameBuffer_ = 0;
|
||||||
for (Token *t = rhs.tokens_; t != rhs.tokens_ + tokenCount_; ++t)
|
}
|
||||||
nameBufferSize += t->length;
|
|
||||||
nameBuffer_ = (Ch*)allocator_->Malloc(nameBufferSize * sizeof(Ch));
|
|
||||||
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
|
|
||||||
|
|
||||||
tokens_ = (Token*)allocator_->Malloc(tokenCount_ * sizeof(Token));
|
|
||||||
std::memcpy(tokens_, rhs.tokens_, tokenCount_ * sizeof(Token));
|
|
||||||
|
|
||||||
// Adjust pointers to name buffer
|
|
||||||
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
|
|
||||||
for (Token *t = rhs.tokens_; t != rhs.tokens_ + tokenCount_; ++t)
|
|
||||||
t->name += diff;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
tokens_ = rhs.tokens_; // User supplied const tokens.
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
//!@name Append token
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Append a token and return a new Pointer
|
||||||
|
/*!
|
||||||
|
\param token Token to be appended.
|
||||||
|
\param allocator Allocator for the newly return Pointer.
|
||||||
|
\return A new Pointer with appended token.
|
||||||
|
*/
|
||||||
|
GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
|
||||||
|
GenericPointer r;
|
||||||
|
r.allocator_ = allocator;
|
||||||
|
Ch *p = r.CopyFromRaw(*this, 1, (token.length + 1) * sizeof(Ch));
|
||||||
|
std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
|
||||||
|
r.tokens_[tokenCount_].name = p;
|
||||||
|
r.tokens_[tokenCount_].length = token.length;
|
||||||
|
r.tokens_[tokenCount_].index = token.index;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Append a name token with length, and return a new Pointer
|
||||||
|
/*!
|
||||||
|
\param name Name to be appended.
|
||||||
|
\param length Length of name.
|
||||||
|
\param allocator Allocator for the newly return Pointer.
|
||||||
|
\return A new Pointer with appended token.
|
||||||
|
*/
|
||||||
|
GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
|
||||||
|
Token token = { name, length, kPointerInvalidIndex };
|
||||||
|
return Append(token, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Append a name token without length, and return a new Pointer
|
||||||
|
/*!
|
||||||
|
\param name Name (const Ch*) to be appended.
|
||||||
|
\param allocator Allocator for the newly return Pointer.
|
||||||
|
\return A new Pointer with appended token.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
|
||||||
|
Append(T* name, Allocator* allocator = 0) const {
|
||||||
|
return Append(name, StrLen(name), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
|
//! Append a name token, and return a new Pointer
|
||||||
|
/*!
|
||||||
|
\param name Name to be appended.
|
||||||
|
\param allocator Allocator for the newly return Pointer.
|
||||||
|
\return A new Pointer with appended token.
|
||||||
|
*/
|
||||||
|
GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
|
||||||
|
return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Append a index token, and return a new Pointer
|
||||||
|
/*!
|
||||||
|
\param index Index to be appended.
|
||||||
|
\param allocator Allocator for the newly return Pointer.
|
||||||
|
\return A new Pointer with appended token.
|
||||||
|
*/
|
||||||
|
GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
|
||||||
|
char buffer[21];
|
||||||
|
SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer;
|
||||||
|
buffer[length] = '\0';
|
||||||
|
|
||||||
|
if (sizeof(Ch) == 1) {
|
||||||
|
Token token = { (Ch*)buffer, length, index };
|
||||||
|
return Append(token, allocator);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Ch name[21];
|
||||||
|
for (size_t i = 0; i <= length; i++)
|
||||||
|
name[i] = buffer[i];
|
||||||
|
Token token = { name, length, index };
|
||||||
|
return Append(token, allocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//!@name Handling Parse Error
|
//!@name Handling Parse Error
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
@ -240,7 +312,7 @@ public:
|
|||||||
for (size_t i = 0; i < tokenCount_; i++) {
|
for (size_t i = 0; i < tokenCount_; i++) {
|
||||||
if (tokens_[i].index != rhs.tokens_[i].index ||
|
if (tokens_[i].index != rhs.tokens_[i].index ||
|
||||||
tokens_[i].length != rhs.tokens_[i].length ||
|
tokens_[i].length != rhs.tokens_[i].length ||
|
||||||
std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length) != 0)
|
(tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -633,6 +705,35 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
//! Clone the content from rhs to this.
|
||||||
|
/*!
|
||||||
|
\param rhs Source pointer.
|
||||||
|
\param extraToken Extra tokens to be allocated.
|
||||||
|
\param extraNameBufferSize Extra name buffer size to be allocated.
|
||||||
|
\return Start of non-occupied name buffer, for storing extra names.
|
||||||
|
*/
|
||||||
|
Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
|
||||||
|
if (!allocator_) // allocator is independently owned.
|
||||||
|
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||||
|
|
||||||
|
size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
|
||||||
|
for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
|
||||||
|
nameBufferSize += t->length;
|
||||||
|
nameBuffer_ = (Ch*)allocator_->Malloc(nameBufferSize * sizeof(Ch)+extraNameBufferSize);
|
||||||
|
std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
|
||||||
|
|
||||||
|
tokenCount_ = rhs.tokenCount_ + extraToken;
|
||||||
|
tokens_ = (Token*)allocator_->Malloc(tokenCount_ * sizeof(Token));
|
||||||
|
std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
|
||||||
|
|
||||||
|
// Adjust pointers to name buffer
|
||||||
|
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
|
||||||
|
for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
|
||||||
|
t->name += diff;
|
||||||
|
|
||||||
|
return nameBuffer_ + nameBufferSize * sizeof(Ch);
|
||||||
|
}
|
||||||
|
|
||||||
//! Check whether a character should be percent-encoded.
|
//! Check whether a character should be percent-encoded.
|
||||||
/*!
|
/*!
|
||||||
According to RFC 3986 2.3 Unreserved Characters.
|
According to RFC 3986 2.3 Unreserved Characters.
|
||||||
@ -740,6 +841,8 @@ private:
|
|||||||
*name++ = c;
|
*name++ = c;
|
||||||
}
|
}
|
||||||
token.length = name - token.name;
|
token.length = name - token.name;
|
||||||
|
if (token.length == 0)
|
||||||
|
isNumber = false;
|
||||||
*name++ = '\0'; // Null terminator
|
*name++ = '\0'; // Null terminator
|
||||||
|
|
||||||
// Second check for index: more than one digit cannot have leading zero
|
// Second check for index: more than one digit cannot have leading zero
|
||||||
|
@ -39,12 +39,22 @@ TEST(Pointer, Parse) {
|
|||||||
EXPECT_EQ(0u, p.GetTokenCount());
|
EXPECT_EQ(0u, p.GetTokenCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Pointer p("/");
|
||||||
|
EXPECT_TRUE(p.IsValid());
|
||||||
|
EXPECT_EQ(1u, p.GetTokenCount());
|
||||||
|
EXPECT_EQ(0u, p.GetTokens()[0].length);
|
||||||
|
EXPECT_STREQ("", p.GetTokens()[0].name);
|
||||||
|
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Pointer p("/foo");
|
Pointer p("/foo");
|
||||||
EXPECT_TRUE(p.IsValid());
|
EXPECT_TRUE(p.IsValid());
|
||||||
EXPECT_EQ(1u, p.GetTokenCount());
|
EXPECT_EQ(1u, p.GetTokenCount());
|
||||||
EXPECT_EQ(3u, p.GetTokens()[0].length);
|
EXPECT_EQ(3u, p.GetTokens()[0].length);
|
||||||
EXPECT_STREQ("foo", p.GetTokens()[0].name);
|
EXPECT_STREQ("foo", p.GetTokens()[0].name);
|
||||||
|
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RAPIDJSON_HAS_STDSTRING
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
@ -54,6 +64,7 @@ TEST(Pointer, Parse) {
|
|||||||
EXPECT_EQ(1u, p.GetTokenCount());
|
EXPECT_EQ(1u, p.GetTokenCount());
|
||||||
EXPECT_EQ(3u, p.GetTokens()[0].length);
|
EXPECT_EQ(3u, p.GetTokens()[0].length);
|
||||||
EXPECT_STREQ("foo", p.GetTokens()[0].name);
|
EXPECT_STREQ("foo", p.GetTokens()[0].name);
|
||||||
|
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -63,6 +74,7 @@ TEST(Pointer, Parse) {
|
|||||||
EXPECT_EQ(2u, p.GetTokenCount());
|
EXPECT_EQ(2u, p.GetTokenCount());
|
||||||
EXPECT_EQ(3u, p.GetTokens()[0].length);
|
EXPECT_EQ(3u, p.GetTokens()[0].length);
|
||||||
EXPECT_STREQ("foo", p.GetTokens()[0].name);
|
EXPECT_STREQ("foo", p.GetTokens()[0].name);
|
||||||
|
EXPECT_EQ(kPointerInvalidIndex, p.GetTokens()[0].index);
|
||||||
EXPECT_EQ(1u, p.GetTokens()[1].length);
|
EXPECT_EQ(1u, p.GetTokens()[1].length);
|
||||||
EXPECT_STREQ("0", p.GetTokens()[1].name);
|
EXPECT_STREQ("0", p.GetTokens()[1].name);
|
||||||
EXPECT_EQ(0u, p.GetTokens()[1].index);
|
EXPECT_EQ(0u, p.GetTokens()[1].index);
|
||||||
@ -481,6 +493,14 @@ TEST(Pointer, Assignment) {
|
|||||||
EXPECT_EQ(1u, q.GetTokens()[1].length);
|
EXPECT_EQ(1u, q.GetTokens()[1].length);
|
||||||
EXPECT_STREQ("0", q.GetTokens()[1].name);
|
EXPECT_STREQ("0", q.GetTokens()[1].name);
|
||||||
EXPECT_EQ(0u, q.GetTokens()[1].index);
|
EXPECT_EQ(0u, q.GetTokens()[1].index);
|
||||||
|
q = q;
|
||||||
|
EXPECT_TRUE(q.IsValid());
|
||||||
|
EXPECT_EQ(2u, q.GetTokenCount());
|
||||||
|
EXPECT_EQ(3u, q.GetTokens()[0].length);
|
||||||
|
EXPECT_STREQ("foo", q.GetTokens()[0].name);
|
||||||
|
EXPECT_EQ(1u, q.GetTokens()[1].length);
|
||||||
|
EXPECT_STREQ("0", q.GetTokens()[1].name);
|
||||||
|
EXPECT_EQ(0u, q.GetTokens()[1].index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Static tokens
|
// Static tokens
|
||||||
@ -498,6 +518,26 @@ TEST(Pointer, Assignment) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Pointer, Append) {
|
||||||
|
{
|
||||||
|
Pointer p;
|
||||||
|
Pointer q = p.Append("foo");
|
||||||
|
EXPECT_TRUE(Pointer("/foo") == q);
|
||||||
|
q = q.Append(0);
|
||||||
|
EXPECT_TRUE(Pointer("/foo/0") == q);
|
||||||
|
q = q.Append("");
|
||||||
|
EXPECT_TRUE(Pointer("/foo/0/") == q);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
|
{
|
||||||
|
Pointer p;
|
||||||
|
Pointer q = p.Append(std::string("foo"));
|
||||||
|
EXPECT_TRUE(Pointer("/foo") == q);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Pointer, Equality) {
|
TEST(Pointer, Equality) {
|
||||||
EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0"));
|
EXPECT_TRUE(Pointer("/foo/0") == Pointer("/foo/0"));
|
||||||
EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1"));
|
EXPECT_FALSE(Pointer("/foo/0") == Pointer("/foo/1"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user